summaryrefslogtreecommitdiffstats
path: root/vendor/orion/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/orion/src')
-rw-r--r--vendor/orion/src/errors.rs140
-rw-r--r--vendor/orion/src/hazardous/aead/chacha20poly1305.rs421
-rw-r--r--vendor/orion/src/hazardous/aead/mod.rs30
-rw-r--r--vendor/orion/src/hazardous/aead/streaming.rs1515
-rw-r--r--vendor/orion/src/hazardous/aead/xchacha20poly1305.rs153
-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/mod.rs24
-rw-r--r--vendor/orion/src/hazardous/ecc/x25519.rs821
-rw-r--r--vendor/orion/src/hazardous/hash/blake2/blake2b.rs414
-rw-r--r--vendor/orion/src/hazardous/hash/blake2/mod.rs442
-rw-r--r--vendor/orion/src/hazardous/hash/mod.rs30
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/mod.rs1062
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha256.rs421
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha384.rs403
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha512.rs424
-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/kdf/argon2i.rs2607
-rw-r--r--vendor/orion/src/hazardous/kdf/hkdf.rs522
-rw-r--r--vendor/orion/src/hazardous/kdf/mod.rs31
-rw-r--r--vendor/orion/src/hazardous/kdf/pbkdf2.rs579
-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/blake2b.rs435
-rw-r--r--vendor/orion/src/hazardous/mac/hmac.rs919
-rw-r--r--vendor/orion/src/hazardous/mac/mod.rs30
-rw-r--r--vendor/orion/src/hazardous/mac/poly1305.rs573
-rw-r--r--vendor/orion/src/hazardous/mod.rs53
-rw-r--r--vendor/orion/src/hazardous/stream/chacha20.rs1331
-rw-r--r--vendor/orion/src/hazardous/stream/mod.rs27
-rw-r--r--vendor/orion/src/hazardous/stream/xchacha20.rs176
-rw-r--r--vendor/orion/src/high_level/aead.rs631
-rw-r--r--vendor/orion/src/high_level/auth.rs212
-rw-r--r--vendor/orion/src/high_level/hash.rs134
-rw-r--r--vendor/orion/src/high_level/hltypes.rs76
-rw-r--r--vendor/orion/src/high_level/kdf.rs222
-rw-r--r--vendor/orion/src/high_level/kex.rs539
-rw-r--r--vendor/orion/src/high_level/mod.rs29
-rw-r--r--vendor/orion/src/high_level/pwhash.rs990
-rw-r--r--vendor/orion/src/lib.rs117
-rw-r--r--vendor/orion/src/test_framework/aead_interface.rs379
-rw-r--r--vendor/orion/src/test_framework/incremental_interface.rs343
-rw-r--r--vendor/orion/src/test_framework/mod.rs30
-rw-r--r--vendor/orion/src/test_framework/streamcipher_interface.rs305
-rw-r--r--vendor/orion/src/typedefs.rs993
-rw-r--r--vendor/orion/src/util/endianness.rs371
-rw-r--r--vendor/orion/src/util/mod.rs186
-rw-r--r--vendor/orion/src/util/u32x4.rs98
-rw-r--r--vendor/orion/src/util/u64x4.rs114
54 files changed, 21923 insertions, 0 deletions
diff --git a/vendor/orion/src/errors.rs b/vendor/orion/src/errors.rs
new file mode 100644
index 0000000..33a5662
--- /dev/null
+++ b/vendor/orion/src/errors.rs
@@ -0,0 +1,140 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+use core::fmt;
+
+#[allow(clippy::derive_partial_eq_without_eq)]
+/// Opaque error.
+#[derive(Clone, Copy, PartialEq)]
+pub struct UnknownCryptoError;
+
+impl fmt::Display for UnknownCryptoError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "UnknownCryptoError")
+ }
+}
+
+impl fmt::Debug for UnknownCryptoError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "UnknownCryptoError")
+ }
+}
+
+#[cfg(feature = "safe_api")]
+impl std::error::Error for UnknownCryptoError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
+
+#[cfg(feature = "safe_api")]
+impl From<getrandom::Error> for UnknownCryptoError {
+ fn from(_: getrandom::Error) -> Self {
+ UnknownCryptoError
+ }
+}
+
+#[cfg(feature = "safe_api")]
+impl From<ct_codecs::Error> for UnknownCryptoError {
+ fn from(_: ct_codecs::Error) -> Self {
+ UnknownCryptoError
+ }
+}
+
+impl From<core::num::ParseIntError> for UnknownCryptoError {
+ fn from(_: core::num::ParseIntError) -> Self {
+ UnknownCryptoError
+ }
+}
+
+#[test]
+#[cfg(feature = "safe_api")]
+// format! is only available with std
+fn test_unknown_crypto_error_debug_display() {
+ // Tests Debug impl through "{:?}"
+ let err = format!("{:?}", UnknownCryptoError);
+ assert_eq!(err, "UnknownCryptoError");
+ // Tests Display impl through "{}"
+ let err = format!("{}", UnknownCryptoError);
+ assert_eq!(err, "UnknownCryptoError");
+}
+
+#[test]
+#[cfg(feature = "safe_api")]
+// format! is only available with std
+fn test_unknown_crypto_from_getrandom() {
+ use core::num::NonZeroU32;
+ // Choose some random error code.
+ let err_code = NonZeroU32::new(12).unwrap();
+ let err_foreign: getrandom::Error = getrandom::Error::from(err_code);
+
+ // Tests Debug impl through "{:?}"
+ let err = format!("{:?}", UnknownCryptoError::from(err_foreign));
+ assert_eq!(err, "UnknownCryptoError");
+ // Tests Display impl through "{}"
+ let err = format!("{}", UnknownCryptoError::from(err_foreign));
+ assert_eq!(err, "UnknownCryptoError");
+}
+
+#[test]
+#[cfg(feature = "safe_api")]
+fn test_source() {
+ use std::error::Error;
+ assert!(UnknownCryptoError.source().is_none());
+}
+
+#[test]
+#[cfg(feature = "safe_api")]
+fn test_unknown_crypto_from_decode_error() {
+ use ct_codecs::Error;
+
+ let err_one = Error::InvalidInput;
+ let err_two = Error::Overflow;
+
+ // Tests Debug impl through "{:?}" and Display impl though "{}"
+ let err = format!(
+ "{:?}:{}",
+ UnknownCryptoError::from(err_one),
+ UnknownCryptoError::from(err_one)
+ );
+ assert_eq!(err, "UnknownCryptoError:UnknownCryptoError");
+ let err = format!(
+ "{:?}:{}",
+ UnknownCryptoError::from(err_two),
+ UnknownCryptoError::from(err_two)
+ );
+ assert_eq!(err, "UnknownCryptoError:UnknownCryptoError");
+}
+
+#[test]
+#[cfg(feature = "safe_api")]
+fn test_unknown_crypto_from_parseint_error() {
+ let err_foreign = "j".parse::<u32>().unwrap_err();
+
+ // Tests Debug impl through "{:?}" and Display impl though "{}"
+ let err = format!(
+ "{:?}:{}",
+ UnknownCryptoError::from(err_foreign.clone()),
+ UnknownCryptoError::from(err_foreign)
+ );
+ assert_eq!(err, "UnknownCryptoError:UnknownCryptoError");
+}
diff --git a/vendor/orion/src/hazardous/aead/chacha20poly1305.rs b/vendor/orion/src/hazardous/aead/chacha20poly1305.rs
new file mode 100644
index 0000000..8211253
--- /dev/null
+++ b/vendor/orion/src/hazardous/aead/chacha20poly1305.rs
@@ -0,0 +1,421 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `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 16 byte
+//! Poly1305 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` + [`POLY1305_OUTSIZE`] when calling [`seal()`].
+//! - The length of `dst_out` is less than `ciphertext_with_tag` - [`POLY1305_OUTSIZE`] when
+//! calling [`open()`].
+//! - The length of `ciphertext_with_tag` is not at least [`POLY1305_OUTSIZE`].
+//! - The received tag does not match the calculated tag when calling [`open()`].
+//! - `plaintext.len()` + [`POLY1305_OUTSIZE`] 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`] when possible.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::aead;
+//!
+//! let secret_key = aead::chacha20poly1305::SecretKey::generate();
+//!
+//! // WARNING: This nonce is only meant for demonstration and should not
+//! // be repeated. Please read the security section.
+//! let nonce = aead::chacha20poly1305::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 16 for the Poly1305
+//! // tag.
+//!
+//! let mut dst_out_ct = [0u8; 15 + 16];
+//! let mut dst_out_pt = [0u8; 15];
+//! // Encrypt and place ciphertext + tag in dst_out_ct
+//! aead::chacha20poly1305::seal(&secret_key, &nonce, message, Some(&ad), &mut dst_out_ct)?;
+//! // Verify tag, if correct then decrypt and place message in dst_out_pt
+//! aead::chacha20poly1305::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`]: xchacha20poly1305
+//! [`POLY1305_OUTSIZE`]: super::mac::poly1305::POLY1305_OUTSIZE
+//! [`seal()`]: chacha20poly1305::seal
+//! [`open()`]: chacha20poly1305::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`]: chacha20poly1305::P_MAX
+//! [`A_MAX`]: chacha20poly1305::A_MAX
+//! [`C_MAX`]: chacha20poly1305::C_MAX
+
+pub use crate::hazardous::stream::chacha20::{Nonce, SecretKey};
+use crate::{
+ errors::UnknownCryptoError,
+ hazardous::{
+ mac::poly1305::{OneTimeKey, Poly1305, POLY1305_KEYSIZE, POLY1305_OUTSIZE},
+ stream::chacha20::{self, ChaCha20, CHACHA_BLOCKSIZE},
+ },
+ util,
+};
+use core::convert::TryInto;
+use zeroize::Zeroizing;
+
+/// The initial counter used for encryption and decryption.
+pub(crate) const ENC_CTR: u32 = 1;
+
+/// The initial counter used for Poly1305 key generation.
+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;
+
+/// The maximum size of the ciphertext (see [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439#section-2.8)).
+pub const C_MAX: u64 = P_MAX + (POLY1305_OUTSIZE as u64);
+
+/// The maximum size of the associated data (see [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439#section-2.8)).
+pub const A_MAX: u64 = u64::MAX;
+
+/// Poly1305 key generation using IETF ChaCha20.
+pub(crate) fn poly1305_key_gen(
+ ctx: &mut ChaCha20,
+ tmp_buffer: &mut Zeroizing<[u8; CHACHA_BLOCKSIZE]>,
+) -> OneTimeKey {
+ ctx.keystream_block(AUTH_CTR, tmp_buffer.as_mut());
+ OneTimeKey::from_slice(&tmp_buffer[..POLY1305_KEYSIZE]).unwrap()
+}
+
+/// Authenticates the ciphertext, ad and their lengths.
+pub(crate) fn process_authentication(
+ auth_ctx: &mut Poly1305,
+ ad: &[u8],
+ ciphertext: &[u8],
+) -> Result<(), UnknownCryptoError> {
+ auth_ctx.process_pad_to_blocksize(ad)?;
+ auth_ctx.process_pad_to_blocksize(ciphertext)?;
+
+ let (ad_len, ct_len): (u64, u64) = match (ad.len().try_into(), ciphertext.len().try_into()) {
+ (Ok(alen), Ok(clen)) => (alen, clen),
+ _ => return Err(UnknownCryptoError),
+ };
+
+ let mut tmp_pad = [0u8; 16];
+ tmp_pad[0..8].copy_from_slice(&ad_len.to_le_bytes());
+ tmp_pad[8..16].copy_from_slice(&ct_len.to_le_bytes());
+ auth_ctx.update(tmp_pad.as_ref())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// AEAD ChaCha20Poly1305 encryption and authentication as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+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(POLY1305_OUTSIZE) {
+ Some(out_min_len) => {
+ if dst_out.len() < out_min_len {
+ return Err(UnknownCryptoError);
+ }
+ }
+ None => return Err(UnknownCryptoError),
+ };
+
+ let mut stream =
+ 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 stream, &mut tmp));
+ let ad_len = ad.len();
+ let ct_len = plaintext.len();
+
+ auth_ctx.process_pad_to_blocksize(ad)?;
+
+ if ct_len != 0 {
+ for (ctr, (p_block, c_block)) in plaintext
+ .chunks(CHACHA_BLOCKSIZE)
+ .zip(dst_out.chunks_mut(CHACHA_BLOCKSIZE))
+ .enumerate()
+ {
+ match ENC_CTR.checked_add(ctr as u32) {
+ Some(counter) => {
+ // See https://github.com/orion-rs/orion/issues/308
+ stream.next_produceable()?;
+ // We know at this point that:
+ // 1) ENC_CTR + ctr does __not__ overflow/panic
+ // 2) ChaCha20 instance will not panic on the next keystream produced
+
+ // Copy keystream directly into the dst_out block in there is
+ // enough space, too avoid copying from `tmp` each time and only
+ // on the last block instead. `c_block` must be full blocksize,
+ // or we leave behind keystream data in it, if `p_block` is not full length
+ // while `c_block` is.
+ if p_block.len() == CHACHA_BLOCKSIZE && c_block.len() == CHACHA_BLOCKSIZE {
+ stream.keystream_block(counter, c_block);
+ xor_slices!(p_block, c_block);
+ auth_ctx.update(c_block)?;
+ }
+
+ // We only pad this last block to the Poly1305 blocksize since `CHACHA_BLOCKSIZE`
+ // already is evenly divisible by 16, so the previous full-length blocks do not matter.
+ if p_block.len() < CHACHA_BLOCKSIZE {
+ stream.keystream_block(counter, tmp.as_mut());
+ xor_slices!(p_block, tmp.as_mut());
+ c_block[..p_block.len()].copy_from_slice(&tmp.as_ref()[..p_block.len()]);
+ auth_ctx.process_pad_to_blocksize(&c_block[..p_block.len()])?;
+ }
+ }
+ None => return Err(UnknownCryptoError),
+ }
+ }
+ }
+
+ let (adlen, ctlen): (u64, u64) = match (ad_len.try_into(), ct_len.try_into()) {
+ (Ok(alen), Ok(clen)) => (alen, clen),
+ _ => return Err(UnknownCryptoError),
+ };
+
+ let mut tmp_pad = [0u8; 16];
+ tmp_pad[0..8].copy_from_slice(&adlen.to_le_bytes());
+ tmp_pad[8..16].copy_from_slice(&ctlen.to_le_bytes());
+ auth_ctx.update(tmp_pad.as_ref())?;
+
+ dst_out[ct_len..(ct_len + POLY1305_OUTSIZE)]
+ .copy_from_slice(auth_ctx.finalize()?.unprotected_as_bytes());
+
+ Ok(())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// AEAD ChaCha20Poly1305 decryption and authentication as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+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() < POLY1305_OUTSIZE {
+ return Err(UnknownCryptoError);
+ }
+ if dst_out.len() < ciphertext_with_tag.len() - POLY1305_OUTSIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ 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() - POLY1305_OUTSIZE;
+ process_authentication(&mut auth_ctx, ad, &ciphertext_with_tag[..ciphertext_len])?;
+ util::secure_cmp(
+ auth_ctx.finalize()?.unprotected_as_bytes(),
+ &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,
+ POLY1305_OUTSIZE,
+ &ad,
+ );
+ test_diff_params_err(&seal, &open, &input, POLY1305_OUTSIZE);
+ true
+ }
+}
+
+// Testing any test vectors that aren't put into library's /tests folder.
+#[cfg(test)]
+mod test_vectors {
+ use super::*;
+
+ #[test]
+ fn rfc8439_poly1305_key_gen_1() {
+ let key = SecretKey::from_slice(&[0u8; 32]).unwrap();
+ let nonce = Nonce::from_slice(&[
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ])
+ .unwrap();
+ let expected = [
+ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86,
+ 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc,
+ 0x8b, 0x77, 0x0d, 0xc7,
+ ];
+
+ let mut chacha20_ctx =
+ ChaCha20::new(key.unprotected_as_bytes(), nonce.as_ref(), true).unwrap();
+ let mut tmp_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+
+ assert_eq!(
+ poly1305_key_gen(&mut chacha20_ctx, &mut tmp_block).unprotected_as_bytes(),
+ expected.as_ref()
+ );
+ }
+
+ #[test]
+ fn rfc8439_poly1305_key_gen_2() {
+ let key = SecretKey::from_slice(&[
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ ])
+ .unwrap();
+ let nonce = Nonce::from_slice(&[
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ ])
+ .unwrap();
+ let expected = [
+ 0xec, 0xfa, 0x25, 0x4f, 0x84, 0x5f, 0x64, 0x74, 0x73, 0xd3, 0xcb, 0x14, 0x0d, 0xa9,
+ 0xe8, 0x76, 0x06, 0xcb, 0x33, 0x06, 0x6c, 0x44, 0x7b, 0x87, 0xbc, 0x26, 0x66, 0xdd,
+ 0xe3, 0xfb, 0xb7, 0x39,
+ ];
+
+ let mut chacha20_ctx =
+ ChaCha20::new(key.unprotected_as_bytes(), nonce.as_ref(), true).unwrap();
+ let mut tmp_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+
+ assert_eq!(
+ poly1305_key_gen(&mut chacha20_ctx, &mut tmp_block).unprotected_as_bytes(),
+ expected.as_ref()
+ );
+ }
+
+ #[test]
+ fn rfc8439_poly1305_key_gen_3() {
+ let key = SecretKey::from_slice(&[
+ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6,
+ 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc,
+ 0x20, 0x70, 0x75, 0xc0,
+ ])
+ .unwrap();
+ let nonce = Nonce::from_slice(&[
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ ])
+ .unwrap();
+ let expected = [
+ 0x96, 0x5e, 0x3b, 0xc6, 0xf9, 0xec, 0x7e, 0xd9, 0x56, 0x08, 0x08, 0xf4, 0xd2, 0x29,
+ 0xf9, 0x4b, 0x13, 0x7f, 0xf2, 0x75, 0xca, 0x9b, 0x3f, 0xcb, 0xdd, 0x59, 0xde, 0xaa,
+ 0xd2, 0x33, 0x10, 0xae,
+ ];
+
+ let mut chacha20_ctx =
+ ChaCha20::new(key.unprotected_as_bytes(), nonce.as_ref(), true).unwrap();
+ let mut tmp_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+
+ assert_eq!(
+ poly1305_key_gen(&mut chacha20_ctx, &mut tmp_block).unprotected_as_bytes(),
+ expected.as_ref()
+ );
+ }
+}
diff --git a/vendor/orion/src/hazardous/aead/mod.rs b/vendor/orion/src/hazardous/aead/mod.rs
new file mode 100644
index 0000000..61d4087
--- /dev/null
+++ b/vendor/orion/src/hazardous/aead/mod.rs
@@ -0,0 +1,30 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// AEAD ChaCha20Poly1305 as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub mod chacha20poly1305;
+
+/// AEAD XChaCha20Poly1305 as specified in the [draft RFC](https://github.com/bikeshedders/xchacha-rfc).
+pub mod xchacha20poly1305;
+
+/// Streaming AEAD based on XChaCha20Poly1305.
+pub mod streaming;
diff --git a/vendor/orion/src/hazardous/aead/streaming.rs b/vendor/orion/src/hazardous/aead/streaming.rs
new file mode 100644
index 0000000..a030f06
--- /dev/null
+++ b/vendor/orion/src/hazardous/aead/streaming.rs
@@ -0,0 +1,1515 @@
+// MIT License
+
+// Copyright (c) 2019-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 implementation is based on and compatible with the ["secretstream" API] of libsodium.
+//!
+//! # Parameters:
+//! - `secret_key`: The secret key.
+//! - `nonce`: The nonce value.
+//! - `ad`: Additional data to authenticate (this is not encrypted and can be `None`).
+//! - `plaintext`: The data to be encrypted.
+//! - `ciphertext`: The encrypted data with, a Poly1305 tag and a [`StreamTag`] indicating its function.
+//! - `dst_out`: Destination array that will hold the `ciphertext`/`plaintext` after encryption/decryption.
+//! - `tag`: Indicates the type of message. The `tag` is a part of the output when encrypting. It
+//! is encrypted and authenticated.
+//!
+//! `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` + [`ABYTES`] when calling [`seal_chunk()`].
+//! - The length of `dst_out` is less than `ciphertext` - [`ABYTES`] when calling [`open_chunk()`].
+//! - The length of the `ciphertext` is less than [`ABYTES`].
+//! - The received mac does not match the calculated mac when calling [`open_chunk()`]. This can
+//! indicate a dropped or reordered message within the stream.
+//! - More than `2^32-3 * 64` bytes of data are processed when sealing/opening a single chunk.
+//! - [`ABYTES`] + `plaintext.len()` overflows when encrypting.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - 64 + (`ciphertext.len()` - [`ABYTES`]) overflows [`u64::MAX`] when decrypting.
+//!
+//! # Security:
+//! - It is critical for security that a given nonce is not re-used with a given key.
+//! - The nonce can be randomly generated using a CSPRNG. [`Nonce::generate()`] can be used for this.
+//! - To securely generate a strong key, use [`SecretKey::generate()`].
+//! - The lengths of the messages are not hidden, only their contents.
+//! - It is recommended to use [`StreamTag::Finish`] as the tag for the last message. This allows the
+//! decrypting side to detect if messages at the end of the stream are lost.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::aead::streaming::*;
+//!
+//! let secret_key = SecretKey::generate();
+//! let nonce = 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 17
+//! // for the mac and tag.
+//! let mut dst_out_ct = [0u8; 15 + ABYTES];
+//! let mut dst_out_pt = [0u8; 15];
+//!
+//! let mut ctx_enc = StreamXChaCha20Poly1305::new(&secret_key, &nonce);
+//!
+//! // Encrypt and place tag + ciphertext + mac in dst_out_ct
+//! ctx_enc.seal_chunk(message, Some(ad), &mut dst_out_ct, &StreamTag::Message)?;
+//!
+//! let mut ctx_dec = StreamXChaCha20Poly1305::new(&secret_key, &nonce);
+//!
+//! // Decrypt and save the tag the message was encrypted with.
+//! let tag = ctx_dec.open_chunk(&dst_out_ct, Some(ad), &mut dst_out_pt)?;
+//!
+//! assert_eq!(tag, StreamTag::Message);
+//! assert_eq!(dst_out_pt.as_ref(), message);
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`SecretKey::generate()`]: super::stream::chacha20::SecretKey::generate
+//! [`Nonce::generate()`]: super::stream::xchacha20::Nonce::generate
+//! [`StreamTag`]: streaming::StreamTag
+//! [`StreamTag::Finish`]: streaming::StreamTag::Finish
+//! [`ABYTES`]: streaming::ABYTES
+//! [`seal_chunk()`]: streaming::StreamXChaCha20Poly1305::seal_chunk
+//! [`open_chunk()`]: streaming::StreamXChaCha20Poly1305::open_chunk
+//! ["secretstream" API]: https://download.libsodium.org/doc/secret-key_cryptography/secretstream
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::aead::chacha20poly1305::poly1305_key_gen;
+use crate::hazardous::mac::poly1305::{Poly1305, Tag as Poly1305Tag, POLY1305_OUTSIZE};
+pub use crate::hazardous::stream::chacha20::SecretKey;
+use crate::hazardous::stream::chacha20::{
+ encrypt as chacha20_enc, encrypt_in_place as chacha20_xor_stream, ChaCha20, Nonce as IETFNonce,
+ CHACHA_BLOCKSIZE, CHACHA_KEYSIZE, HCHACHA_NONCESIZE, IETF_CHACHA_NONCESIZE,
+};
+use crate::hazardous::stream::xchacha20::subkey_and_nonce;
+pub use crate::hazardous::stream::xchacha20::Nonce;
+use core::convert::TryFrom;
+use subtle::ConstantTimeEq;
+use zeroize::{Zeroize, Zeroizing};
+
+#[derive(Debug, Clone, Copy)]
+/// Tag that indicates the type of message.
+pub enum StreamTag {
+ /// A message with no special meaning.
+ Message,
+ /// Marks that the message is the end of a set of messages. Allows the decrypting site to
+ /// start working with this data.
+ Push,
+ /// Derives a new secret key and forgets the one used for earlier encryption/decryption
+ /// operations.
+ Rekey,
+ /// Indicates the end of a stream. Also does a rekey.
+ Finish,
+}
+
+impl StreamTag {
+ #[inline]
+ /// Return the tag as a byte.
+ pub fn as_byte(&self) -> u8 {
+ match *self {
+ StreamTag::Message => 0b0000_0000,
+ StreamTag::Push => 0b0000_0001,
+ StreamTag::Rekey => 0b0000_0010,
+ StreamTag::Finish => 0b0000_0011, /* StreamTag::Push.as_byte() | StreamTag::Rekey.as_bytes() */
+ }
+ }
+}
+
+impl TryFrom<u8> for StreamTag {
+ type Error = UnknownCryptoError;
+
+ fn try_from(byte: u8) -> Result<Self, Self::Error> {
+ match byte {
+ 0b0000_0000 => Ok(Self::Message),
+ 0b0000_0001 => Ok(Self::Push),
+ 0b0000_0010 => Ok(Self::Rekey),
+ 0b0000_0011 => Ok(Self::Finish),
+ _ => Err(UnknownCryptoError),
+ }
+ }
+}
+
+impl PartialEq<StreamTag> for StreamTag {
+ fn eq(&self, other: &StreamTag) -> bool {
+ (self.as_byte().ct_eq(&other.as_byte())).into()
+ }
+}
+
+/// The size of the internal counter.
+const COUNTERBYTES: usize = 4;
+/// The size of the internal nonce.
+const INONCEBYTES: usize = 8;
+/// The size of a StreamTag.
+pub const TAG_SIZE: usize = 1;
+/// Size of additional data appended to each message.
+pub const ABYTES: usize = POLY1305_OUTSIZE + TAG_SIZE;
+
+/// Padding size that gives the needed bytes to pad `input` to an integral
+/// multiple of 16.
+fn padding(input: usize) -> usize {
+ if input == 0 {
+ return 0;
+ }
+
+ let rem = input % 16;
+
+ if rem != 0 {
+ 16 - rem
+ } else {
+ 0
+ }
+}
+
+/// Streaming XChaCha20Poly1305 state.
+pub struct StreamXChaCha20Poly1305 {
+ key: SecretKey,
+ counter: u32,
+ inonce: [u8; INONCEBYTES],
+}
+
+impl core::fmt::Debug for StreamXChaCha20Poly1305 {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "StreamXChaCha20Poly1305 {{ key: [***OMITTED***], counter: [***OMITTED***], inonce: [***OMITTED***]",
+ )
+ }
+}
+
+impl StreamXChaCha20Poly1305 {
+ /// Return a nonce used with ChaCha20Poly1305 based on the internal counter
+ /// and inonce.
+ fn get_nonce(&self) -> IETFNonce {
+ let mut nonce = [0u8; IETF_CHACHA_NONCESIZE];
+ nonce[..COUNTERBYTES].copy_from_slice(&self.counter.to_le_bytes());
+ nonce[COUNTERBYTES..].copy_from_slice(&self.inonce);
+
+ IETFNonce::from(nonce)
+ }
+
+ /// Generates a Poly1305 tag for a message.
+ fn generate_auth_tag(
+ &mut self,
+ text: &[u8],
+ ad: &[u8],
+ msglen: usize,
+ block: &[u8],
+ textpos: usize,
+ ) -> Result<Poly1305Tag, UnknownCryptoError> {
+ debug_assert!(text.len() >= textpos + msglen);
+
+ let mut chacha20_ctx = ChaCha20::new(
+ self.key.unprotected_as_bytes(),
+ self.get_nonce().as_ref(),
+ true,
+ )
+ .unwrap();
+ let mut tmp_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+
+ let mut pad = [0u8; 16];
+ let mut poly = Poly1305::new(&poly1305_key_gen(&mut chacha20_ctx, &mut tmp_block));
+
+ poly.process_pad_to_blocksize(ad)?;
+ poly.update(block)?;
+ poly.update(&text[textpos..(textpos + msglen)])?;
+ poly.update(&pad[..padding(CHACHA_BLOCKSIZE.wrapping_sub(msglen))])?;
+ pad[..8].copy_from_slice(&(ad.len() as u64).to_le_bytes());
+ pad[8..16].copy_from_slice(
+ &((CHACHA_BLOCKSIZE as u64)
+ .checked_add(msglen as u64)
+ .unwrap())
+ .to_le_bytes(),
+ );
+ poly.update(&pad)?;
+
+ poly.finalize()
+ }
+
+ /// Update internal inonce and counter. Performs rekey on overflowing counter and
+ /// designated tags.
+ fn advance_state(
+ &mut self,
+ mac: &Poly1305Tag,
+ tag: &StreamTag,
+ ) -> Result<(), UnknownCryptoError> {
+ xor_slices!(mac.unprotected_as_bytes()[..INONCEBYTES], self.inonce);
+ self.counter = self.counter.wrapping_add(1);
+ if bool::from(
+ !(tag.as_byte() & StreamTag::Rekey.as_byte()).ct_eq(&0u8) | self.counter.ct_eq(&0u32),
+ ) {
+ self.rekey()?;
+ };
+
+ Ok(())
+ }
+
+ /// Initialize a `StreamXChaCha20Poly1305` struct with a given secret key and nonce.
+ pub fn new(secret_key: &SecretKey, nonce: &Nonce) -> Self {
+ let mut inonce = [0u8; INONCEBYTES];
+ inonce.copy_from_slice(&nonce.as_ref()[HCHACHA_NONCESIZE..]);
+
+ Self {
+ key: subkey_and_nonce(secret_key, nonce).0,
+ counter: 1,
+ inonce,
+ }
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Derives a new secret key used for encryption and decryption.
+ pub fn rekey(&mut self) -> Result<(), UnknownCryptoError> {
+ let mut new_key_and_inonce = [0u8; CHACHA_KEYSIZE + INONCEBYTES];
+ new_key_and_inonce[..CHACHA_KEYSIZE].copy_from_slice(self.key.unprotected_as_bytes());
+ new_key_and_inonce[CHACHA_KEYSIZE..].copy_from_slice(&self.inonce);
+
+ chacha20_xor_stream(&self.key, &self.get_nonce(), 0, &mut new_key_and_inonce)?;
+
+ self.key = SecretKey::from_slice(&new_key_and_inonce[..CHACHA_KEYSIZE]).unwrap();
+ self.inonce
+ .copy_from_slice(&new_key_and_inonce[CHACHA_KEYSIZE..]);
+ self.counter = 1;
+ new_key_and_inonce.zeroize();
+
+ Ok(())
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Encrypt and authenticate a single message and tag.
+ pub fn seal_chunk(
+ &mut self,
+ plaintext: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+ tag: &StreamTag,
+ ) -> Result<(), UnknownCryptoError> {
+ let msglen = plaintext.len();
+ match ABYTES.checked_add(msglen) {
+ Some(out_min_len) => {
+ if dst_out.len() < out_min_len {
+ return Err(UnknownCryptoError);
+ }
+ }
+ None => return Err(UnknownCryptoError),
+ };
+
+ let mut block = [0u8; CHACHA_BLOCKSIZE];
+ let ad = ad.unwrap_or(&[0u8; 0]);
+
+ let macpos = TAG_SIZE + msglen;
+ let nonce = self.get_nonce();
+
+ block[0] = tag.as_byte();
+ chacha20_xor_stream(&self.key, &nonce, 1, &mut block)?;
+ dst_out[0] = block[0];
+
+ if msglen != 0 {
+ chacha20_enc(&self.key, &nonce, 2, plaintext, &mut dst_out[TAG_SIZE..])?;
+ }
+
+ let mac = self.generate_auth_tag(dst_out, ad, msglen, &block, TAG_SIZE)?;
+ dst_out[macpos..(macpos + POLY1305_OUTSIZE)].copy_from_slice(mac.unprotected_as_bytes());
+
+ self.advance_state(&mac, tag)
+ }
+
+ #[allow(clippy::range_plus_one)]
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Authenticate and decrypt a single message and tag.
+ pub fn open_chunk(
+ &mut self,
+ ciphertext: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<StreamTag, UnknownCryptoError> {
+ if ciphertext.len() < ABYTES {
+ return Err(UnknownCryptoError);
+ }
+
+ let msglen = ciphertext.len() - ABYTES;
+ if dst_out.len() < msglen {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut block = [0u8; CHACHA_BLOCKSIZE];
+ let ad = ad.unwrap_or(&[0u8; 0]);
+
+ let macpos = TAG_SIZE + msglen;
+ let nonce = self.get_nonce();
+
+ block[0] = ciphertext[0];
+ chacha20_xor_stream(&self.key, &nonce, 1, &mut block)?;
+ let tag = StreamTag::try_from(block[0])?;
+ block[0] = ciphertext[0];
+ let mac = self.generate_auth_tag(ciphertext, ad, msglen, &block, TAG_SIZE)?;
+ if !(mac == &ciphertext[macpos..macpos + mac.len()]) {
+ return Err(UnknownCryptoError);
+ }
+ if msglen != 0 {
+ chacha20_enc(
+ &self.key,
+ &nonce,
+ 2,
+ &ciphertext[TAG_SIZE..(TAG_SIZE + msglen)],
+ dst_out,
+ )?;
+ }
+ self.advance_state(&mac, &tag)?;
+
+ Ok(tag)
+ }
+}
+
+#[cfg(test)]
+mod public {
+ #[cfg(feature = "safe_api")]
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let secret_key = SecretKey::generate();
+ let nonce = Nonce::generate();
+ let initial_state = StreamXChaCha20Poly1305::new(&secret_key, &nonce);
+ let debug = format!("{:?}", initial_state);
+ let expected = "StreamXChaCha20Poly1305 { key: [***OMITTED***], counter: [***OMITTED***], inonce: [***OMITTED***]";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod proptest {
+ use crate::errors::UnknownCryptoError;
+ use crate::hazardous::aead::streaming::{
+ Nonce, SecretKey, StreamTag, StreamXChaCha20Poly1305, ABYTES,
+ };
+ use crate::test_framework::aead_interface::*;
+ use core::convert::TryFrom;
+
+ fn seal(
+ sk: &SecretKey,
+ nonce: &Nonce,
+ input: &[u8],
+ ad: Option<&[u8]>,
+ output: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ let mut state = StreamXChaCha20Poly1305::new(sk, nonce);
+ state.seal_chunk(input, ad, output, &StreamTag::Message)
+ }
+
+ fn open(
+ sk: &SecretKey,
+ nonce: &Nonce,
+ input: &[u8],
+ ad: Option<&[u8]>,
+ output: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ let mut state = StreamXChaCha20Poly1305::new(sk, nonce);
+ state.open_chunk(input, ad, output)?;
+
+ Ok(())
+ }
+
+ #[quickcheck]
+ 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, ABYTES, &ad);
+
+ true
+ }
+
+ #[quickcheck]
+ fn prop_same_input_twice_diff_output(input: Vec<u8>, ad: Vec<u8>) -> bool {
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::generate(), &Nonce::generate());
+
+ let mut ct1 = vec![0u8; input.len() + ABYTES];
+ let mut ct2 = ct1.clone();
+
+ ctx.seal_chunk(&input, Some(&ad), &mut ct1, &StreamTag::Message)
+ .unwrap();
+ ctx.seal_chunk(&input, Some(&ad), &mut ct2, &StreamTag::Message)
+ .unwrap();
+
+ ct1 != ct2
+ }
+
+ #[quickcheck]
+ fn prop_tag(byte: u8) -> bool {
+ match byte {
+ 0u8 => StreamTag::try_from(byte).unwrap() == StreamTag::Message,
+ 1u8 => StreamTag::try_from(byte).unwrap() == StreamTag::Push,
+ 2u8 => StreamTag::try_from(byte).unwrap() == StreamTag::Rekey,
+ 3u8 => StreamTag::try_from(byte).unwrap() == StreamTag::Finish,
+ _ => StreamTag::try_from(byte).is_err(),
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_padding {
+ use super::*;
+ #[test]
+ fn test_length_padding() {
+ assert_eq!(padding(0), 0);
+ assert_eq!(padding(1), 15);
+ assert_eq!(padding(2), 14);
+ assert_eq!(padding(3), 13);
+ assert_eq!(padding(4), 12);
+ assert_eq!(padding(5), 11);
+ assert_eq!(padding(6), 10);
+ assert_eq!(padding(7), 9);
+ assert_eq!(padding(8), 8);
+ assert_eq!(padding(9), 7);
+ assert_eq!(padding(10), 6);
+ assert_eq!(padding(11), 5);
+ assert_eq!(padding(12), 4);
+ assert_eq!(padding(13), 3);
+ assert_eq!(padding(14), 2);
+ assert_eq!(padding(15), 1);
+ assert_eq!(padding(16), 0);
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ // The usize that padding() returns should always
+ // be what remains to make input a multiple of 16 in length.
+ fn prop_padding_result(input: usize) -> bool {
+ let rem = padding(input);
+
+ // NOTE: It is possible to have an input size that will
+ // have padding() return a remainder that cannot be added
+ // to the original input size without overflowing its usize (tested on 64-bit).
+ // This is okay, because nothing is added to the returned value of padding()
+ // in generate_auth_tag. It's only ever added in this test. The remainder is still
+ // valid regardless, which is also "proven" by the test below.
+ // So to test the below assumption, we can only ever do so if it doesn't overflow,
+ // hence the needed check.
+ //
+ // See also below test test_inputsize_79().
+ //
+ // (Trigger here with: size = 18446744073709551601)
+ // (Trigger seal_chunk/open_chunk with input of size 79 (check usage of wrapping_sub))
+
+ match input.checked_add(rem) {
+ Some(res) => res % 16 == 0,
+ None => true, // The case we cannot test
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ // padding() should never return a usize above 15.
+ // The usize must always be in range of 0..=15.
+ fn prop_result_never_above_15(input: usize) -> bool {
+ padding(input) < 16
+ }
+ }
+
+ #[test]
+ fn test_inputsize_79() {
+ // Generated with libsodium
+ let sk = [
+ 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8, 56u8, 57u8, 97u8, 98u8, 99u8, 100u8, 101u8,
+ 102u8, 103u8, 104u8, 105u8, 106u8, 107u8, 108u8, 109u8, 111u8, 110u8, 112u8, 113u8,
+ 114u8, 115u8, 116u8, 117u8, 118u8, 0u8,
+ ];
+ let nonce = [
+ 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8,
+ 97u8, 98u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let input: [u8; 79] = [
+ 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8,
+ 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8,
+ 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8,
+ 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8,
+ 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8,
+ 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8, 101u8, 102u8, 98u8, 101u8,
+ 0u8,
+ ];
+ let output: [u8; 96] = [
+ 252u8, 178u8, 0u8, 210u8, 9u8, 149u8, 109u8, 242u8, 161u8, 71u8, 231u8, 3u8, 175u8,
+ 17u8, 24u8, 148u8, 40u8, 118u8, 80u8, 107u8, 96u8, 105u8, 191u8, 34u8, 86u8, 101u8,
+ 33u8, 53u8, 116u8, 51u8, 220u8, 199u8, 26u8, 140u8, 80u8, 251u8, 81u8, 125u8, 160u8,
+ 186u8, 197u8, 26u8, 72u8, 217u8, 22u8, 205u8, 150u8, 103u8, 233u8, 204u8, 79u8, 59u8,
+ 137u8, 18u8, 93u8, 25u8, 189u8, 131u8, 137u8, 231u8, 123u8, 56u8, 186u8, 215u8, 33u8,
+ 41u8, 241u8, 146u8, 248u8, 44u8, 253u8, 253u8, 177u8, 115u8, 51u8, 23u8, 166u8, 64u8,
+ 6u8, 213u8, 174u8, 254u8, 55u8, 101u8, 185u8, 178u8, 89u8, 121u8, 175u8, 221u8, 174u8,
+ 75u8, 188u8, 65u8, 41u8, 75u8,
+ ];
+
+ let secret_key = SecretKey::from_slice(&sk).unwrap();
+ let nonce = Nonce::from_slice(&nonce).unwrap();
+
+ let mut state = StreamXChaCha20Poly1305::new(&secret_key, &nonce);
+ let mut dst_out = [0u8; 96];
+ state
+ .seal_chunk(&input, None, &mut dst_out, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(dst_out.as_ref(), output.as_ref());
+
+ state = StreamXChaCha20Poly1305::new(&secret_key, &nonce);
+ let mut dst_out_pt = [0u8; 79];
+ state.open_chunk(&output, None, &mut dst_out_pt).unwrap();
+ assert_eq!(dst_out_pt.as_ref(), input.as_ref());
+ }
+
+ // Test values were generated using libsodium. See /tests/test_generation/
+
+ const KEY: [u8; 32] = [
+ 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8, 56u8, 57u8, 97u8, 98u8, 99u8, 100u8, 101u8,
+ 102u8, 103u8, 104u8, 105u8, 106u8, 107u8, 108u8, 109u8, 111u8, 110u8, 112u8, 113u8, 114u8,
+ 115u8, 116u8, 117u8, 118u8, 0u8,
+ ];
+ const NONCE: [u8; 24] = [
+ 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8, 98u8, 97u8,
+ 98u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+
+ const DEFAULT_MSG: [u8; 51] = [
+ 68u8, 101u8, 102u8, 97u8, 117u8, 108u8, 116u8, 32u8, 109u8, 101u8, 115u8, 115u8, 97u8,
+ 103u8, 101u8, 32u8, 116u8, 111u8, 32u8, 116u8, 101u8, 115u8, 116u8, 32u8, 115u8, 116u8,
+ 114u8, 101u8, 97u8, 109u8, 105u8, 110u8, 103u8, 32u8, 65u8, 69u8, 65u8, 68u8, 32u8, 101u8,
+ 110u8, 99u8, 114u8, 121u8, 112u8, 116u8, 105u8, 111u8, 110u8, 46u8, 0u8,
+ ];
+
+ #[test]
+ fn test_tag() {
+ assert_eq!(StreamTag::Message.as_byte(), 0u8);
+ assert_eq!(StreamTag::Push.as_byte(), 1u8);
+ assert_eq!(StreamTag::Rekey.as_byte(), 2u8);
+ assert_eq!(StreamTag::Finish.as_byte(), 3u8);
+ assert!(StreamTag::try_from(4u8).is_err());
+ }
+
+ #[test]
+ fn test_seal_open_with_explicit_rekey() {
+ // Encrypt stream
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(
+ s.key,
+ [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8,
+ 116u8, 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8,
+ 219u8, 33u8, 44u8, 68u8, 91u8, 135u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,].as_ref()
+ );
+
+ // 1st StreamTag::Message
+ let plaintext1: [u8; 6] = [116u8, 101u8, 115u8, 116u8, 49u8, 0u8];
+ let mut out1 = [0u8; 6 + ABYTES];
+ s.seal_chunk(&plaintext1, None, &mut out1, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8,
+ 116u8, 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8,
+ 219u8, 33u8, 44u8, 68u8, 91u8, 135u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [2u8, 0u8, 0u8, 0u8, 88u8, 186u8, 23u8, 231u8, 10u8, 253u8, 79u8, 71u8,].as_ref()
+ );
+ assert_eq!(
+ out1,
+ [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8,
+ 156u8, 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ]
+ );
+
+ // 2nd StreamTag::Message
+ let plaintext2: [u8; 20] = [
+ 116u8, 104u8, 105u8, 115u8, 32u8, 105u8, 115u8, 32u8, 108u8, 111u8, 110u8, 103u8,
+ 101u8, 114u8, 32u8, 116u8, 101u8, 120u8, 116u8, 0u8,
+ ];
+ let mut out2 = [0u8; 20 + ABYTES];
+ s.seal_chunk(&plaintext2, None, &mut out2, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8,
+ 116u8, 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8,
+ 219u8, 33u8, 44u8, 68u8, 91u8, 135u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [3u8, 0u8, 0u8, 0u8, 73u8, 199u8, 255u8, 159u8, 213u8, 205u8, 201u8, 51u8,].as_ref()
+ );
+ assert_eq!(
+ out2.as_ref(),
+ [
+ 243u8, 52u8, 124u8, 173u8, 133u8, 44u8, 99u8, 244u8, 250u8, 89u8, 101u8, 142u8,
+ 59u8, 49u8, 221u8, 52u8, 176u8, 214u8, 13u8, 247u8, 86u8, 17u8, 125u8, 232u8,
+ 120u8, 223u8, 48u8, 134u8, 116u8, 8u8, 207u8, 180u8, 241u8, 76u8, 26u8, 33u8,
+ 207u8,
+ ]
+ .as_ref()
+ );
+
+ // 3rd StreamTag::Message
+ let plaintext3: [u8; 2] = [49u8, 0u8];
+ let mut out3 = [0u8; 2 + ABYTES];
+ s.seal_chunk(&plaintext3, None, &mut out3, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8,
+ 116u8, 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8,
+ 219u8, 33u8, 44u8, 68u8, 91u8, 135u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [4u8, 0u8, 0u8, 0u8, 229u8, 134u8, 216u8, 143u8, 117u8, 43u8, 216u8, 142u8,].as_ref()
+ );
+ assert_eq!(
+ out3.as_ref(),
+ [
+ 237u8, 198u8, 240u8, 172u8, 65u8, 39u8, 16u8, 160u8, 230u8, 17u8, 189u8, 54u8,
+ 93u8, 173u8, 243u8, 103u8, 185u8, 53u8, 219u8,
+ ]
+ .as_ref()
+ );
+
+ // Explicit rekey
+ s.rekey().unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 55u8, 213u8, 132u8, 57u8, 116u8, 28u8, 19u8, 214u8, 59u8, 159u8, 188u8, 185u8,
+ 201u8, 153u8, 70u8, 17u8, 149u8, 199u8, 55u8, 34u8, 164u8, 54u8, 200u8, 241u8,
+ 157u8, 71u8, 218u8, 62u8, 37u8, 37u8, 8u8, 126u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [1u8, 0u8, 0u8, 0u8, 250u8, 25u8, 191u8, 166u8, 103u8, 98u8, 187u8, 196u8,].as_ref()
+ );
+
+ // 4th StreamTag::Message
+ let plaintext4: [u8; 23] = [
+ 102u8, 105u8, 114u8, 115u8, 116u8, 32u8, 116u8, 101u8, 120u8, 116u8, 32u8, 97u8, 102u8,
+ 116u8, 101u8, 114u8, 32u8, 114u8, 101u8, 107u8, 101u8, 121u8, 0u8,
+ ];
+ let mut out4 = [0u8; 23 + ABYTES];
+ s.seal_chunk(&plaintext4, None, &mut out4, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 55u8, 213u8, 132u8, 57u8, 116u8, 28u8, 19u8, 214u8, 59u8, 159u8, 188u8, 185u8,
+ 201u8, 153u8, 70u8, 17u8, 149u8, 199u8, 55u8, 34u8, 164u8, 54u8, 200u8, 241u8,
+ 157u8, 71u8, 218u8, 62u8, 37u8, 37u8, 8u8, 126u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [2u8, 0u8, 0u8, 0u8, 70u8, 193u8, 51u8, 16u8, 173u8, 151u8, 68u8, 48u8,].as_ref()
+ );
+ assert_eq!(
+ out4.as_ref(),
+ [
+ 210u8, 9u8, 37u8, 11u8, 182u8, 190u8, 88u8, 175u8, 0u8, 12u8, 125u8, 154u8, 63u8,
+ 104u8, 166u8, 255u8, 231u8, 12u8, 233u8, 57u8, 206u8, 99u8, 82u8, 23u8, 188u8,
+ 216u8, 140u8, 182u8, 202u8, 245u8, 255u8, 244u8, 104u8, 89u8, 216u8, 168u8, 68u8,
+ 130u8, 12u8, 80u8,
+ ]
+ .as_ref()
+ );
+
+ // 5th StreamTag::Message
+ let plaintext5: [u8; 36] = [
+ 116u8, 104u8, 105u8, 115u8, 32u8, 105u8, 115u8, 32u8, 116u8, 104u8, 101u8, 32u8, 115u8,
+ 101u8, 99u8, 111u8, 110u8, 100u8, 32u8, 116u8, 101u8, 120u8, 116u8, 32u8, 97u8, 102u8,
+ 116u8, 101u8, 114u8, 32u8, 114u8, 101u8, 107u8, 101u8, 121u8, 0u8,
+ ];
+ let mut out5 = [0u8; 36 + ABYTES];
+ s.seal_chunk(&plaintext5, None, &mut out5, &StreamTag::Message)
+ .unwrap();
+ assert_eq!(
+ s.key,
+ [
+ 55u8, 213u8, 132u8, 57u8, 116u8, 28u8, 19u8, 214u8, 59u8, 159u8, 188u8, 185u8,
+ 201u8, 153u8, 70u8, 17u8, 149u8, 199u8, 55u8, 34u8, 164u8, 54u8, 200u8, 241u8,
+ 157u8, 71u8, 218u8, 62u8, 37u8, 37u8, 8u8, 126u8,
+ ]
+ .as_ref()
+ );
+ assert_eq!(
+ s.get_nonce(),
+ [3u8, 0u8, 0u8, 0u8, 119u8, 231u8, 54u8, 137u8, 64u8, 159u8, 87u8, 77u8,].as_ref()
+ );
+ assert_eq!(
+ out5.as_ref(),
+ [
+ 122u8, 17u8, 56u8, 176u8, 124u8, 172u8, 219u8, 248u8, 0u8, 37u8, 184u8, 242u8,
+ 65u8, 248u8, 69u8, 242u8, 158u8, 119u8, 20u8, 17u8, 225u8, 10u8, 107u8, 240u8,
+ 210u8, 134u8, 6u8, 182u8, 91u8, 243u8, 243u8, 20u8, 30u8, 205u8, 232u8, 167u8,
+ 247u8, 49u8, 38u8, 5u8, 153u8, 237u8, 8u8, 19u8, 125u8, 226u8, 190u8, 189u8, 167u8,
+ 33u8, 189u8, 74u8, 189u8,
+ ]
+ .as_ref()
+ );
+
+ // Decrypt stream
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+
+ let mut plain_out1 = [0u8; 6];
+ assert_eq!(
+ s.open_chunk(&out1, None, &mut plain_out1).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(plain_out1.as_ref(), plaintext1.as_ref());
+
+ let mut plain_out2 = [0u8; 20];
+ assert_eq!(
+ s.open_chunk(&out2, None, &mut plain_out2).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(plain_out2.as_ref(), plaintext2.as_ref());
+
+ let mut plain_out3 = [0u8; 2];
+ assert_eq!(
+ s.open_chunk(&out3, None, &mut plain_out3).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(plain_out3.as_ref(), plaintext3.as_ref());
+
+ s.rekey().unwrap();
+
+ let mut plain_out4 = [0u8; 23];
+ assert_eq!(
+ s.open_chunk(&out4, None, &mut plain_out4).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(plain_out4.as_ref(), plaintext4.as_ref());
+
+ let mut plain_out5 = [0u8; 36];
+ assert_eq!(
+ s.open_chunk(&out5, None, &mut plain_out5).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(plain_out5.as_ref(), plaintext5.as_ref());
+ }
+
+ #[test]
+ fn test_reorder_or_drop_msg() {
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let plaintext1 = [116u8, 101u8, 115u8, 116u8, 49u8, 0u8];
+ let plaintext2 = [
+ 116u8, 104u8, 105u8, 115u8, 32u8, 105u8, 115u8, 32u8, 108u8, 111u8, 110u8, 103u8,
+ 101u8, 114u8, 32u8, 116u8, 101u8, 120u8, 116u8, 0u8,
+ ];
+ let cipher1 = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let cipher2 = [
+ 243u8, 52u8, 124u8, 173u8, 133u8, 44u8, 99u8, 244u8, 250u8, 89u8, 101u8, 142u8, 59u8,
+ 49u8, 221u8, 52u8, 176u8, 214u8, 13u8, 247u8, 86u8, 17u8, 125u8, 232u8, 120u8, 223u8,
+ 48u8, 134u8, 116u8, 8u8, 207u8, 180u8, 241u8, 76u8, 26u8, 33u8, 207u8,
+ ];
+
+ let cipher3 = [
+ 237u8, 198u8, 240u8, 172u8, 65u8, 39u8, 16u8, 160u8, 230u8, 17u8, 189u8, 54u8, 93u8,
+ 173u8, 243u8, 103u8, 185u8, 53u8, 219u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert_eq!(
+ ctx.open_chunk(&cipher1, None, &mut plain_out1).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(&plain_out1, &plaintext1);
+ // Out of order decryption happens here
+ let mut plain_out3 = [0u8; 19 - ABYTES];
+ assert!(ctx.open_chunk(&cipher3, None, &mut plain_out3).is_err());
+
+ let mut plain_out2 = [0u8; 37 - ABYTES];
+ assert_eq!(
+ ctx.open_chunk(&cipher2, None, &mut plain_out2).unwrap(),
+ StreamTag::Message
+ );
+ assert_eq!(&plain_out2, &plaintext2);
+ }
+
+ #[test]
+ fn test_err_on_diff_tag() {
+ // Crate 4 different sealed chunks, sealed with the same input except for
+ // the StreamTag.
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut dst_out_msg = [0u8; 51 + ABYTES];
+ ctx.seal_chunk(
+ DEFAULT_MSG.as_ref(),
+ None,
+ &mut dst_out_msg,
+ &StreamTag::Message,
+ )
+ .unwrap();
+
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut dst_out_push = [0u8; 51 + ABYTES];
+ ctx.seal_chunk(
+ DEFAULT_MSG.as_ref(),
+ None,
+ &mut dst_out_push,
+ &StreamTag::Push,
+ )
+ .unwrap();
+
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut dst_out_rekey = [0u8; 51 + ABYTES];
+ ctx.seal_chunk(
+ DEFAULT_MSG.as_ref(),
+ None,
+ &mut dst_out_rekey,
+ &StreamTag::Rekey,
+ )
+ .unwrap();
+
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut dst_out_finish = [0u8; 51 + ABYTES];
+ ctx.seal_chunk(
+ DEFAULT_MSG.as_ref(),
+ None,
+ &mut dst_out_finish,
+ &StreamTag::Finish,
+ )
+ .unwrap();
+
+ // Swap the StreamTags, which should decrypt successfully but fail authentication as
+ // it does not match the Poly1305 Tag calculated.
+ let mut dst_out_pt = [0u8; 51];
+
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert!(ctx.open_chunk(&dst_out_msg, None, &mut dst_out_pt).is_ok());
+
+ dst_out_msg[0] = dst_out_push[0];
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert!(ctx.open_chunk(&dst_out_msg, None, &mut dst_out_pt).is_err());
+
+ dst_out_msg[0] = dst_out_rekey[0];
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert!(ctx.open_chunk(&dst_out_msg, None, &mut dst_out_pt).is_err());
+
+ dst_out_msg[0] = dst_out_finish[0];
+ ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert!(ctx.open_chunk(&dst_out_msg, None, &mut dst_out_pt).is_err());
+ }
+
+ #[test]
+ fn test_err_on_modified_message_tag() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_ok());
+
+ // Reset state
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ // Change tag to Push plaintext. Originally was Message and encrypted.
+ cipher1[0] = StreamTag::Push.as_byte();
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_err());
+ }
+
+ #[test]
+ fn test_err_on_diff_secret_key() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from(NONCE));
+ let cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_err());
+ }
+
+ #[test]
+ fn test_err_on_diff_nonce() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from([0u8; 24]));
+ let cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_err());
+ }
+
+ #[test]
+ fn test_err_on_modified_mac() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_ok());
+
+ // Reset state
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ // Change MAC
+ let macpos = cipher1.len() - 1;
+ cipher1[macpos] |= 0b1010_1010;
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_err());
+ }
+
+ #[test]
+ fn test_err_on_modified_cipher() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ let mut cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_ok());
+
+ // Reset state
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ // Change something in the ciphertext
+ cipher1[5] |= 0b1010_1010;
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_err());
+ }
+
+ #[test]
+ fn test_err_on_diff_ad() {
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ // This ciphertext was constructed without AD
+ let cipher1: [u8; 23] = [
+ 252u8, 164u8, 0u8, 196u8, 27u8, 198u8, 8u8, 57u8, 216u8, 118u8, 134u8, 104u8, 156u8,
+ 45u8, 71u8, 161u8, 199u8, 28u8, 79u8, 145u8, 19u8, 239u8, 4u8,
+ ];
+ let mut plain_out1 = [0u8; 23 - ABYTES];
+ assert!(s.open_chunk(&cipher1, None, &mut plain_out1).is_ok());
+
+ // Reset state
+ let mut s = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert!(s
+ .open_chunk(&cipher1, Some(&[1u8; 1]), &mut plain_out1)
+ .is_err());
+ }
+
+ #[test]
+ fn test_encrypting_same_message_different_output() {
+ let input = [0u8, 1u8, 2u8, 3u8];
+ let mut cipher = [0u8; 4 + ABYTES];
+ let mut cipher2 = [0u8; 4 + ABYTES];
+ let mut state_enc =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ state_enc
+ .seal_chunk(&input, None, &mut cipher, &StreamTag::Message)
+ .unwrap();
+ state_enc
+ .seal_chunk(&input, None, &mut cipher2, &StreamTag::Message)
+ .unwrap();
+ assert_ne!(cipher, cipher2);
+ }
+
+ #[test]
+ fn test_encrypting_same_message_explicit_rekey() {
+ let input = [0u8, 1u8, 2u8, 3u8];
+ let mut cipher = [0u8; 4 + ABYTES];
+ let mut cipher2 = [0u8; 4 + ABYTES];
+ let mut state_enc =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ state_enc
+ .seal_chunk(&input, None, &mut cipher, &StreamTag::Message)
+ .unwrap();
+ let mut state_enc =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ state_enc.rekey().unwrap();
+ state_enc
+ .seal_chunk(&input, None, &mut cipher2, &StreamTag::Message)
+ .unwrap();
+ assert_ne!(cipher, cipher2);
+ }
+
+ #[test]
+ // This cannot be tested in AeadTestRunner as it assumes empty
+ // ciphertext to be invalid.
+ fn test_seal_empty_and_open() {
+ let mut state_enc =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ let mut cipher = [0u8; ABYTES];
+ state_enc
+ .seal_chunk(&[0u8; 0], None, &mut cipher, &StreamTag::Message)
+ .unwrap();
+
+ let mut state_dec =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+
+ let mut out = [0u8; ABYTES];
+ assert!(state_dec.open_chunk(&cipher, None, &mut out).is_ok());
+ }
+
+ #[test]
+ // This cannot be tested in AeadTestRunner as it assumes empty
+ // ciphertext to be invalid. This also tests that input to open_chunk
+ // requires the tagsize only, and not tagsize + 1.
+ fn test_seal_open_zero_length_both() {
+ let mut state_enc =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ let mut out = [0u8; ABYTES];
+ state_enc
+ .seal_chunk(&[0u8; 0], None, &mut out, &StreamTag::Message)
+ .unwrap();
+ let mut state_dec =
+ StreamXChaCha20Poly1305::new(&SecretKey::from([0u8; 32]), &Nonce::from([0u8; 24]));
+ let mut dst_out = [0u8; 0];
+ // Only the attached tag is decrypted and authenticated. But it is
+ // not placed in dst_out.
+ assert!(state_dec.open_chunk(&out, None, &mut dst_out).is_ok());
+ assert!(dst_out.is_empty());
+ assert_eq!(dst_out, [0u8; 0]);
+ }
+
+ #[test]
+ fn test_new_to_msg_with_tag_final() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let after_internal_key: [u8; 32] = [
+ 168u8, 19u8, 24u8, 25u8, 196u8, 239u8, 73u8, 251u8, 36u8, 135u8, 89u8, 117u8, 2u8,
+ 50u8, 208u8, 173u8, 177u8, 61u8, 147u8, 201u8, 97u8, 47u8, 74u8, 149u8, 21u8, 166u8,
+ 227u8, 53u8, 24u8, 101u8, 251u8, 201u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 149u8, 246u8, 165u8, 228u8, 252u8, 41u8, 183u8, 89u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 255u8, 148u8, 0u8, 209u8, 14u8, 130u8, 100u8, 227u8, 231u8, 72u8, 231u8, 21u8, 186u8,
+ 18u8, 26u8, 148u8, 110u8, 96u8, 90u8, 46u8, 114u8, 110u8, 169u8, 51u8, 16u8, 116u8,
+ 48u8, 34u8, 119u8, 48u8, 212u8, 203u8, 18u8, 137u8, 21u8, 223u8, 114u8, 94u8, 129u8,
+ 255u8, 198u8, 22u8, 78u8, 206u8, 9u8, 223u8, 135u8, 107u8, 224u8, 192u8, 4u8, 94u8,
+ 100u8, 12u8, 28u8, 232u8, 44u8, 133u8, 81u8, 145u8, 176u8, 153u8, 17u8, 215u8, 180u8,
+ 79u8, 24u8, 79u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(ctx.key.unprotected_as_bytes(), before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Finish)
+ .unwrap();
+
+ assert_eq!(ctx.key.unprotected_as_bytes(), after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_new_to_msg_with_tag_rekey() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let after_internal_key: [u8; 32] = [
+ 39u8, 159u8, 44u8, 102u8, 206u8, 161u8, 116u8, 119u8, 163u8, 187u8, 45u8, 209u8, 172u8,
+ 224u8, 237u8, 93u8, 9u8, 197u8, 138u8, 242u8, 195u8, 183u8, 253u8, 169u8, 86u8, 46u8,
+ 161u8, 32u8, 71u8, 244u8, 51u8, 222u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 161u8, 222u8, 206u8, 42u8, 195u8, 117u8, 85u8, 88u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 254u8, 148u8, 0u8, 209u8, 14u8, 130u8, 100u8, 227u8, 231u8, 72u8, 231u8, 21u8, 186u8,
+ 18u8, 26u8, 148u8, 110u8, 96u8, 90u8, 46u8, 114u8, 110u8, 169u8, 51u8, 16u8, 116u8,
+ 48u8, 34u8, 119u8, 48u8, 212u8, 203u8, 18u8, 137u8, 21u8, 223u8, 114u8, 94u8, 129u8,
+ 255u8, 198u8, 22u8, 78u8, 206u8, 9u8, 223u8, 135u8, 107u8, 224u8, 192u8, 4u8, 94u8,
+ 187u8, 26u8, 216u8, 136u8, 169u8, 121u8, 52u8, 215u8, 102u8, 180u8, 177u8, 255u8, 69u8,
+ 135u8, 172u8, 22u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(ctx.key.unprotected_as_bytes(), before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Rekey)
+ .unwrap();
+
+ assert_eq!(ctx.key.unprotected_as_bytes(), after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_new_to_msg_with_tag_final_twice() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let after_internal_key: [u8; 32] = [
+ 162u8, 54u8, 231u8, 162u8, 170u8, 199u8, 53u8, 228u8, 224u8, 121u8, 138u8, 154u8, 17u8,
+ 252u8, 83u8, 49u8, 52u8, 25u8, 105u8, 51u8, 112u8, 3u8, 62u8, 217u8, 163u8, 194u8,
+ 15u8, 113u8, 155u8, 17u8, 7u8, 250u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 107u8, 7u8, 226u8, 104u8, 227u8, 227u8, 7u8, 100u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 119u8, 255u8, 30u8, 46u8, 10u8, 174u8, 158u8, 45u8, 225u8, 116u8, 158u8, 172u8, 175u8,
+ 198u8, 241u8, 34u8, 87u8, 52u8, 80u8, 230u8, 175u8, 133u8, 217u8, 132u8, 169u8, 75u8,
+ 68u8, 249u8, 86u8, 87u8, 86u8, 68u8, 33u8, 250u8, 148u8, 117u8, 43u8, 10u8, 22u8,
+ 125u8, 198u8, 6u8, 231u8, 5u8, 86u8, 199u8, 29u8, 214u8, 215u8, 74u8, 71u8, 244u8,
+ 194u8, 50u8, 98u8, 209u8, 136u8, 235u8, 79u8, 113u8, 54u8, 101u8, 105u8, 14u8, 178u8,
+ 146u8, 23u8, 229u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(ctx.key.unprotected_as_bytes(), before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Finish)
+ .unwrap();
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Finish)
+ .unwrap();
+
+ assert_eq!(ctx.key.unprotected_as_bytes(), after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_new_to_msg_with_tag_rekey_twice() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let after_internal_key: [u8; 32] = [
+ 35u8, 207u8, 156u8, 185u8, 84u8, 18u8, 253u8, 160u8, 229u8, 242u8, 126u8, 247u8, 235u8,
+ 193u8, 36u8, 121u8, 42u8, 247u8, 85u8, 108u8, 107u8, 143u8, 210u8, 194u8, 109u8, 46u8,
+ 107u8, 47u8, 186u8, 127u8, 123u8, 46u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 198u8, 222u8, 225u8, 73u8, 93u8, 233u8, 75u8, 181u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 1u8, 171u8, 81u8, 78u8, 97u8, 128u8, 134u8, 65u8, 126u8, 237u8, 31u8, 59u8, 6u8, 76u8,
+ 85u8, 119u8, 69u8, 183u8, 129u8, 184u8, 101u8, 246u8, 151u8, 0u8, 92u8, 171u8, 38u8,
+ 164u8, 215u8, 120u8, 75u8, 169u8, 254u8, 207u8, 198u8, 138u8, 118u8, 68u8, 89u8, 231u8,
+ 38u8, 220u8, 26u8, 210u8, 220u8, 102u8, 8u8, 245u8, 205u8, 152u8, 39u8, 155u8, 36u8,
+ 115u8, 127u8, 79u8, 54u8, 246u8, 154u8, 2u8, 24u8, 208u8, 83u8, 232u8, 143u8, 234u8,
+ 51u8, 194u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(ctx.key.unprotected_as_bytes(), before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Rekey)
+ .unwrap();
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Rekey)
+ .unwrap();
+
+ assert_eq!(ctx.key.unprotected_as_bytes(), after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_new_to_msg_with_tag_push() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let after_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 2u8, 0u8, 0u8, 0u8, 118u8, 75u8, 245u8, 72u8, 68u8, 15u8, 117u8, 29u8,
+ ];
+ let after_internal_counter: [u8; 4] = [2u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 253u8, 148u8, 0u8, 209u8, 14u8, 130u8, 100u8, 227u8, 231u8, 72u8, 231u8, 21u8, 186u8,
+ 18u8, 26u8, 148u8, 110u8, 96u8, 90u8, 46u8, 114u8, 110u8, 169u8, 51u8, 16u8, 116u8,
+ 48u8, 34u8, 119u8, 48u8, 212u8, 203u8, 18u8, 137u8, 21u8, 223u8, 114u8, 94u8, 129u8,
+ 255u8, 198u8, 22u8, 78u8, 206u8, 9u8, 223u8, 135u8, 107u8, 224u8, 192u8, 4u8, 94u8,
+ 23u8, 41u8, 148u8, 41u8, 38u8, 110u8, 23u8, 29u8, 29u8, 207u8, 81u8, 40u8, 215u8,
+ 190u8, 64u8, 222u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ assert_eq!(ctx.key, before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce().as_ref(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Push)
+ .unwrap();
+
+ assert_eq!(ctx.key, after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce().as_ref(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_counter_overflow_with_tag_msg() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 255u8, 255u8, 255u8, 255u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [255u8, 255u8, 255u8, 255u8];
+ let after_internal_key: [u8; 32] = [
+ 48u8, 109u8, 58u8, 2u8, 7u8, 92u8, 20u8, 239u8, 137u8, 218u8, 220u8, 62u8, 74u8, 47u8,
+ 118u8, 162u8, 61u8, 234u8, 35u8, 242u8, 40u8, 2u8, 243u8, 149u8, 188u8, 249u8, 180u8,
+ 242u8, 228u8, 139u8, 163u8, 76u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 36u8, 9u8, 22u8, 61u8, 226u8, 117u8, 46u8, 156u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 131u8, 93u8, 90u8, 220u8, 186u8, 163u8, 161u8, 113u8, 238u8, 31u8, 49u8, 63u8, 12u8,
+ 101u8, 64u8, 221u8, 255u8, 190u8, 206u8, 20u8, 155u8, 140u8, 72u8, 180u8, 4u8, 199u8,
+ 170u8, 178u8, 21u8, 212u8, 238u8, 60u8, 110u8, 233u8, 44u8, 24u8, 105u8, 216u8, 234u8,
+ 132u8, 103u8, 31u8, 222u8, 244u8, 214u8, 180u8, 224u8, 206u8, 148u8, 114u8, 100u8,
+ 161u8, 57u8, 6u8, 49u8, 199u8, 242u8, 58u8, 28u8, 253u8, 199u8, 16u8, 246u8, 86u8,
+ 116u8, 22u8, 66u8, 91u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ ctx.counter = u32::MAX;
+ assert_eq!(ctx.key, before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Message)
+ .unwrap();
+
+ assert_eq!(ctx.key, after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_counter_overflow_with_tag_rekey() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 255u8, 255u8, 255u8, 255u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [255u8, 255u8, 255u8, 255u8];
+ let after_internal_key: [u8; 32] = [
+ 115u8, 83u8, 132u8, 174u8, 130u8, 252u8, 214u8, 242u8, 239u8, 140u8, 231u8, 231u8,
+ 111u8, 228u8, 182u8, 88u8, 124u8, 109u8, 210u8, 61u8, 48u8, 22u8, 215u8, 232u8, 180u8,
+ 174u8, 180u8, 216u8, 174u8, 209u8, 222u8, 8u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 188u8, 188u8, 116u8, 239u8, 177u8, 113u8, 89u8, 218u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 129u8, 93u8, 90u8, 220u8, 186u8, 163u8, 161u8, 113u8, 238u8, 31u8, 49u8, 63u8, 12u8,
+ 101u8, 64u8, 221u8, 255u8, 190u8, 206u8, 20u8, 155u8, 140u8, 72u8, 180u8, 4u8, 199u8,
+ 170u8, 178u8, 21u8, 212u8, 238u8, 60u8, 110u8, 233u8, 44u8, 24u8, 105u8, 216u8, 234u8,
+ 132u8, 103u8, 31u8, 222u8, 244u8, 214u8, 180u8, 224u8, 206u8, 148u8, 114u8, 100u8,
+ 161u8, 107u8, 212u8, 93u8, 14u8, 123u8, 181u8, 233u8, 248u8, 139u8, 61u8, 100u8, 73u8,
+ 40u8, 14u8, 226u8, 118u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ ctx.counter = u32::MAX;
+ assert_eq!(ctx.key.unprotected_as_bytes(), before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Rekey)
+ .unwrap();
+
+ assert_eq!(ctx.key.unprotected_as_bytes(), after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_counter_overflow_with_tag_final() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 255u8, 255u8, 255u8, 255u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [255u8, 255u8, 255u8, 255u8];
+ let after_internal_key: [u8; 32] = [
+ 181u8, 99u8, 219u8, 38u8, 136u8, 29u8, 61u8, 72u8, 122u8, 0u8, 111u8, 182u8, 254u8,
+ 74u8, 225u8, 183u8, 250u8, 200u8, 34u8, 169u8, 252u8, 92u8, 107u8, 85u8, 144u8, 12u8,
+ 203u8, 19u8, 166u8, 41u8, 168u8, 26u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 230u8, 194u8, 178u8, 201u8, 13u8, 110u8, 57u8, 106u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 128u8, 93u8, 90u8, 220u8, 186u8, 163u8, 161u8, 113u8, 238u8, 31u8, 49u8, 63u8, 12u8,
+ 101u8, 64u8, 221u8, 255u8, 190u8, 206u8, 20u8, 155u8, 140u8, 72u8, 180u8, 4u8, 199u8,
+ 170u8, 178u8, 21u8, 212u8, 238u8, 60u8, 110u8, 233u8, 44u8, 24u8, 105u8, 216u8, 234u8,
+ 132u8, 103u8, 31u8, 222u8, 244u8, 214u8, 180u8, 224u8, 206u8, 148u8, 114u8, 100u8,
+ 161u8, 137u8, 59u8, 244u8, 49u8, 191u8, 114u8, 208u8, 246u8, 237u8, 83u8, 155u8, 66u8,
+ 2u8, 10u8, 178u8, 132u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ ctx.counter = u32::MAX;
+ assert_eq!(ctx.key, before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Finish)
+ .unwrap();
+
+ assert_eq!(ctx.key, after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn test_counter_overflow_with_tag_push() {
+ let before_internal_key: [u8; 32] = [
+ 23u8, 45u8, 143u8, 75u8, 14u8, 65u8, 110u8, 208u8, 6u8, 34u8, 38u8, 33u8, 64u8, 116u8,
+ 179u8, 244u8, 8u8, 121u8, 32u8, 23u8, 87u8, 135u8, 147u8, 246u8, 88u8, 52u8, 219u8,
+ 33u8, 44u8, 68u8, 91u8, 135u8,
+ ];
+ let before_internal_nonce: [u8; 12] = [
+ 255u8, 255u8, 255u8, 255u8, 97u8, 98u8, 97u8, 97u8, 98u8, 97u8, 98u8, 0u8,
+ ];
+ let before_internal_counter: [u8; 4] = [255u8, 255u8, 255u8, 255u8];
+ let after_internal_key: [u8; 32] = [
+ 251u8, 165u8, 61u8, 114u8, 68u8, 126u8, 68u8, 202u8, 143u8, 101u8, 78u8, 242u8, 164u8,
+ 171u8, 209u8, 209u8, 227u8, 5u8, 181u8, 244u8, 141u8, 167u8, 137u8, 0u8, 228u8, 122u8,
+ 149u8, 109u8, 129u8, 240u8, 174u8, 128u8,
+ ];
+ let after_internal_nonce: [u8; 12] = [
+ 1u8, 0u8, 0u8, 0u8, 228u8, 204u8, 203u8, 245u8, 146u8, 107u8, 101u8, 124u8,
+ ];
+ let after_internal_counter: [u8; 4] = [1u8, 0u8, 0u8, 0u8];
+ let out: [u8; 68] = [
+ 130u8, 93u8, 90u8, 220u8, 186u8, 163u8, 161u8, 113u8, 238u8, 31u8, 49u8, 63u8, 12u8,
+ 101u8, 64u8, 221u8, 255u8, 190u8, 206u8, 20u8, 155u8, 140u8, 72u8, 180u8, 4u8, 199u8,
+ 170u8, 178u8, 21u8, 212u8, 238u8, 60u8, 110u8, 233u8, 44u8, 24u8, 105u8, 216u8, 234u8,
+ 132u8, 103u8, 31u8, 222u8, 244u8, 214u8, 180u8, 224u8, 206u8, 148u8, 114u8, 100u8,
+ 161u8, 82u8, 109u8, 199u8, 234u8, 54u8, 248u8, 2u8, 251u8, 41u8, 39u8, 45u8, 80u8,
+ 78u8, 18u8, 18u8, 105u8,
+ ];
+
+ let mut ctx = StreamXChaCha20Poly1305::new(&SecretKey::from(KEY), &Nonce::from(NONCE));
+ ctx.counter = u32::MAX;
+ assert_eq!(ctx.key, before_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), before_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(before_internal_counter));
+
+ let mut actual = [0u8; 68];
+ ctx.seal_chunk(DEFAULT_MSG.as_ref(), None, &mut actual, &StreamTag::Push)
+ .unwrap();
+
+ assert_eq!(ctx.key, after_internal_key.as_ref());
+ assert_eq!(ctx.get_nonce(), after_internal_nonce.as_ref());
+ assert_eq!(ctx.counter, u32::from_le_bytes(after_internal_counter));
+ assert_eq!(actual.as_ref(), out.as_ref());
+ }
+}
diff --git a/vendor/orion/src/hazardous/aead/xchacha20poly1305.rs b/vendor/orion/src/hazardous/aead/xchacha20poly1305.rs
new file mode 100644
index 0000000..1d110f7
--- /dev/null
+++ b/vendor/orion/src/hazardous/aead/xchacha20poly1305.rs
@@ -0,0 +1,153 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `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 16 byte
+//! Poly1305 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` + [`POLY1305_OUTSIZE`] when calling [`seal()`].
+//! - The length of `dst_out` is less than `ciphertext_with_tag` - [`POLY1305_OUTSIZE`] when
+//! calling [`open()`].
+//! - The length of the `ciphertext_with_tag` is not at least [`POLY1305_OUTSIZE`].
+//! - The received tag does not match the calculated tag when calling [`open()`].
+//! - `plaintext.len()` + [`POLY1305_OUTSIZE`] overflows when calling [`seal()`].
+//! - Converting `usize` to `u64` would be a lossy conversion.
+//! - `plaintext.len() >` [`chacha20poly1305::P_MAX`]
+//! - `ad.len() >` [`chacha20poly1305::A_MAX`]
+//! - `ciphertext_with_tag.len() >` [`chacha20poly1305::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::aead;
+//!
+//! let secret_key = aead::xchacha20poly1305::SecretKey::generate();
+//! let nonce = aead::xchacha20poly1305::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 16 for the Poly1305
+//! // tag.
+//!
+//! let mut dst_out_ct = [0u8; 15 + 16];
+//! let mut dst_out_pt = [0u8; 15];
+//! // Encrypt and place ciphertext + tag in dst_out_ct
+//! aead::xchacha20poly1305::seal(&secret_key, &nonce, message, Some(&ad), &mut dst_out_ct)?;
+//! // Verify tag, if correct then decrypt and place message in dst_out_pt
+//! aead::xchacha20poly1305::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
+//! [`POLY1305_OUTSIZE`]: super::mac::poly1305::POLY1305_OUTSIZE
+//! [`seal()`]: xchacha20poly1305::seal
+//! [`open()`]: xchacha20poly1305::open
+//! [libsodium docs]: https://download.libsodium.org/doc/secret-key_cryptography/aead#additional-data
+
+use crate::hazardous::stream::xchacha20::subkey_and_nonce;
+pub use crate::hazardous::stream::{chacha20::SecretKey, xchacha20::Nonce};
+use crate::{errors::UnknownCryptoError, hazardous::aead::chacha20poly1305};
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// AEAD XChaCha20Poly1305 encryption as specified in the [draft RFC](https://github.com/bikeshedders/xchacha-rfc).
+pub fn seal(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ plaintext: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ let (subkey, ietf_nonce) = subkey_and_nonce(secret_key, nonce);
+ chacha20poly1305::seal(&subkey, &ietf_nonce, plaintext, ad, dst_out)
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// AEAD XChaCha20Poly1305 decryption as specified in the [draft RFC](https://github.com/bikeshedders/xchacha-rfc).
+pub fn open(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ ciphertext_with_tag: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ let (subkey, ietf_nonce) = subkey_and_nonce(secret_key, nonce);
+ chacha20poly1305::open(&subkey, &ietf_nonce, ciphertext_with_tag, ad, dst_out)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+mod public {
+ use super::*;
+ use crate::hazardous::mac::poly1305::POLY1305_OUTSIZE;
+ 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,
+ POLY1305_OUTSIZE,
+ &ad,
+ );
+ test_diff_params_err(&seal, &open, &input, POLY1305_OUTSIZE);
+ true
+ }
+}
diff --git a/vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs b/vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs
new file mode 100644
index 0000000..19cef00
--- /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 0000000..270821b
--- /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 0000000..25d3c32
--- /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/mod.rs b/vendor/orion/src/hazardous/ecc/mod.rs
new file mode 100644
index 0000000..a539b67
--- /dev/null
+++ b/vendor/orion/src/hazardous/ecc/mod.rs
@@ -0,0 +1,24 @@
+// MIT License
+
+// Copyright (c) 2021-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.
+
+/// Diffie-Hellman key exchange over Curve25519 as specified in the [RFC 7748](https://datatracker.ietf.org/doc/html/rfc7748).
+pub mod x25519;
diff --git a/vendor/orion/src/hazardous/ecc/x25519.rs b/vendor/orion/src/hazardous/ecc/x25519.rs
new file mode 100644
index 0000000..806777f
--- /dev/null
+++ b/vendor/orion/src/hazardous/ecc/x25519.rs
@@ -0,0 +1,821 @@
+// MIT License
+
+// Copyright (c) 2021-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:
+//! - `private_key`: The private key used in key agreement.
+//! - `public_key`: The public key used in key agreement.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The `key_agreement()` operation results in an all-zero output.
+//!
+//! # Security:
+//! - Multiple different `private_key`/`public_key` pairs can produce the same shared key. Therefore,
+//! using the resulting `SharedKey`, directly from `key_agreement()`, is not recommended. This is handled
+//! automatically in [`orion::kex`].
+//! - To securely generate a strong key, use [`PrivateKey::generate()`].
+//!
+//! # Recommendation:
+//! - It is recommended to use [`orion::kex`] when possible.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::ecc::x25519::{PrivateKey, PublicKey, SharedKey, key_agreement};
+//! use core::convert::TryFrom;
+//!
+//! // Alice generates a private key and computes the corresponding public key
+//! let alice_sk = PrivateKey::generate();
+//! let alice_pk = PublicKey::try_from(&alice_sk)?;
+//!
+//! // Bob does the same
+//! let bob_sk = PrivateKey::generate();
+//! let bob_pk = PublicKey::try_from(&bob_sk)?;
+//!
+//! // They both compute a shared key using the others public key
+//! let alice_shared = key_agreement(&alice_sk, &bob_pk)?;
+//! let bob_shared = key_agreement(&bob_sk, &alice_pk)?;
+//!
+//! assert_eq!(alice_shared, bob_shared);
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`PrivateKey::generate()`]: crate::hazardous::ecc::x25519::PrivateKey::generate
+//! [`orion::kex`]: crate::kex
+
+use crate::errors::UnknownCryptoError;
+use crate::util::secure_cmp;
+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;
+
+/// The size of a private key used in X25519.
+pub const PRIVATE_KEY_SIZE: usize = 32;
+
+/// The size of a shared key used in X25519.
+pub const SHARED_KEY_SIZE: usize = 32;
+
+/// u-coordinate of the base point.
+const BASEPOINT: [u8; 32] = [
+ 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+/// The result of computing a shared secret with a low order point.
+const LOW_ORDER_POINT_RESULT: [u8; 32] = [0u8; 32];
+
+#[derive(Clone, Copy)]
+/// Represent an element in the curve field.
+struct FieldElement(fiat_25519_tight_field_element);
+
+impl Eq for FieldElement {}
+
+impl PartialEq for FieldElement {
+ fn eq(&self, other: &Self) -> bool {
+ use subtle::ConstantTimeEq;
+ self.as_bytes().ct_eq(&other.as_bytes()).into()
+ }
+}
+
+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 {
+ 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);
+
+ fiat_25519_carry_mul(&mut ret, &self_relaxed, &rhs_relaxed);
+
+ Self(ret)
+ }
+}
+
+/// The function fiat_25519_add adds two field elements.
+impl Add for FieldElement {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+ let mut ret_add = fiat_25519_loose_field_element([0u64; 5]);
+
+ fiat_25519_add(&mut ret_add, &self.0, &rhs.0);
+ fiat_25519_carry(&mut ret, &ret_add);
+
+ Self(ret)
+ }
+}
+
+/// The function fiat_25519_sub subtracts two field elements.
+impl Sub for FieldElement {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+ let mut ret_sub = fiat_25519_loose_field_element([0u64; 5]);
+
+ fiat_25519_sub(&mut ret_sub, &self.0, &rhs.0);
+ fiat_25519_carry(&mut ret, &ret_sub);
+
+ Self(ret)
+ }
+}
+
+impl FieldElement {
+ /// Create a `FieldElement` that is `0`.
+ fn zero() -> Self {
+ Self(fiat_25519_tight_field_element([
+ 0u64, 0u64, 0u64, 0u64, 0u64,
+ ]))
+ }
+
+ /// Create a `FieldElement` that is `1`.
+ fn one() -> Self {
+ Self(fiat_25519_tight_field_element([
+ 1u64, 0u64, 0u64, 0u64, 0u64,
+ ]))
+ }
+
+ /// Serialize the `FieldElement` as a byte-array.
+ fn as_bytes(&self) -> [u8; 32] {
+ // The function fiat_25519_to_bytes serializes a field element to bytes in little-endian order.
+ use fiat_curve25519_u64::fiat_25519_to_bytes;
+
+ let mut ret = [0u8; 32];
+ fiat_25519_to_bytes(&mut ret, &self.0);
+
+ ret
+ }
+
+ /// Deserialize the `FieldElement` from a byte-array in little-endian.
+ ///
+ /// Masks the MSB in the final byte of the input bytes.
+ fn from_bytes(bytes: &[u8; 32]) -> Self {
+ // The function fiat_25519_from_bytes deserializes a field element from bytes in little-endian order
+ use fiat_curve25519_u64::fiat_25519_from_bytes;
+
+ let mut temp = [0u8; 32];
+ temp.copy_from_slice(bytes);
+ 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 = fiat_25519_tight_field_element([0u64; 5]);
+ fiat_25519_from_bytes(&mut ret, &temp);
+
+ Self(ret)
+ }
+
+ /// A conditional-swap operation.
+ fn conditional_swap(swap: u8, a: &mut Self, b: &mut Self) {
+ // The function fiat_25519_selectznz is a multi-limb conditional select.
+ use fiat_curve25519_u64::fiat_25519_selectznz;
+
+ // SAFETY: This is a part of fiat input bounds.
+ debug_assert!(swap == 1 || swap == 0);
+
+ let tmp_a = *a;
+ let tmp_b = *b;
+
+ 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 {
+ let mut self_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+
+ 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 {
+ let mut self_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+
+ fiat_25519_relax(&mut self_relaxed, &self.0);
+ fiat_25519_carry_scmul_121666(&mut ret, &self_relaxed);
+
+ Self(ret)
+ }
+
+ /// Compute the multiplicative inverse of the `FieldElement`.
+ ///
+ /// Ref: https://github.com/golang/crypto/blob/0c34fe9e7dc2486962ef9867e3edb3503537209f/curve25519/curve25519_generic.go#L718
+ fn invert(&mut self) {
+ let mut t0 = self.square();
+ let mut t1 = t0.square();
+ t1 = t1.square();
+
+ t1 = *self * t1;
+ t0 = t0 * t1;
+ let mut t2 = t0.square();
+
+ t1 = t1 * t2;
+ t2 = t1.square();
+ for _ in 1..5 {
+ t2 = t2.square();
+ }
+ t1 = t2 * t1;
+ t2 = t1.square();
+ for _ in 1..10 {
+ t2 = t2.square();
+ }
+ t2 = t2 * t1;
+ let mut t3 = t2.square();
+ for _ in 1..20 {
+ t3 = t3.square();
+ }
+ t2 = t3 * t2;
+ t2 = t2.square();
+ for _ in 1..10 {
+ t2 = t2.square();
+ }
+ t1 = t2 * t1;
+ t2 = t1.square();
+ for _ in 1..50 {
+ t2 = t2.square();
+ }
+
+ t2 = t2 * t1;
+ t3 = t2.square();
+ for _ in 1..100 {
+ t3 = t3.square();
+ }
+ t2 = t3 * t2;
+ t2 = t2.square();
+ for _ in 1..50 {
+ t2 = t2.square();
+ }
+ t1 = t2 * t1;
+ t1 = t1.square();
+ for _ in 1..5 {
+ t1 = t1.square();
+ }
+
+ *self = t1 * t0;
+ }
+}
+
+#[derive(Clone)]
+/// Represents a Scalar decoded from a byte array.
+struct Scalar([u8; PRIVATE_KEY_SIZE]);
+
+impl Drop for Scalar {
+ fn drop(&mut self) {
+ use zeroize::Zeroize;
+ self.0.iter_mut().zeroize();
+ }
+}
+
+impl PartialEq for Scalar {
+ fn eq(&self, other: &Self) -> bool {
+ use subtle::ConstantTimeEq;
+ self.0.ct_eq(&other.0).into()
+ }
+}
+
+impl Eq for Scalar {}
+
+impl Scalar {
+ /// Create a scalar from some byte-array.
+ /// The scalar is clamped according to the RFC.
+ ///
+ /// Ref: https://www.ietf.org/rfc/rfc7748.html#section-5
+ fn from_slice(slice: &[u8]) -> Result<Scalar, UnknownCryptoError> {
+ if slice.len() != PRIVATE_KEY_SIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut ret = [0u8; PRIVATE_KEY_SIZE];
+ ret.copy_from_slice(slice);
+ // Clamp
+ ret[0] &= 248;
+ ret[31] &= 127;
+ ret[31] |= 64;
+
+ Ok(Self(ret))
+ }
+}
+
+/// Scalar multiplication using the Montgomery Ladder (a.k.a "scalarmult")
+///
+/// Refs:
+/// - https://eprint.iacr.org/2020/956.pdf
+/// - https://eprint.iacr.org/2017/212.pdf
+/// - https://github.com/golang/crypto/blob/0c34fe9e7dc2486962ef9867e3edb3503537209f/curve25519/curve25519_generic.go#L779
+fn mont_ladder(scalar: &Scalar, point: FieldElement) -> FieldElement {
+ let x1 = point;
+ let mut x2 = FieldElement::one();
+ let mut x3 = x1;
+ let mut z3 = FieldElement::one();
+ let mut z2 = FieldElement::zero();
+ let mut tmp0: FieldElement;
+ let mut tmp1: FieldElement;
+
+ let mut swap: u8 = 0;
+
+ for idx in (0..=254).rev() {
+ let bit = (scalar.0[idx >> 3] >> (idx & 7)) & 1;
+ swap ^= bit;
+ FieldElement::conditional_swap(swap, &mut x2, &mut x3);
+ FieldElement::conditional_swap(swap, &mut z2, &mut z3);
+ swap = bit;
+
+ tmp0 = x3 - z3;
+ tmp1 = x2 - z2;
+ x2 = x2 + z2;
+ z2 = x3 + z3;
+ z3 = tmp0 * x2;
+ z2 = z2 * tmp1;
+ tmp0 = tmp1.square();
+ tmp1 = x2.square();
+ x3 = z3 + z2;
+ z2 = z3 - z2;
+ x2 = tmp1 * tmp0;
+ tmp1 = tmp1 - tmp0;
+ z2 = z2.square();
+ z3 = tmp1.mul_121666();
+ x3 = x3.square();
+ tmp0 = tmp0 + z3;
+ z3 = x1 * z2;
+ z2 = tmp1 * tmp0;
+ }
+
+ FieldElement::conditional_swap(swap, &mut x2, &mut x3);
+ FieldElement::conditional_swap(swap, &mut z2, &mut z3);
+
+ z2.invert();
+ x2 = x2 * z2;
+
+ x2
+}
+
+#[allow(clippy::derive_partial_eq_without_eq)]
+// NOTE: FieldElement contains a constant-time PartialEq<FieldElement> impl.
+/// A type that represents a `PublicKey` that X25519 uses.
+///
+/// This type holds a field element and is used internally as the u-coordinate.
+/// As the RFC mandates, the most significant bit of the last byte is masked.
+///
+/// # Errors:
+/// An error will be returned if:
+/// - `slice` is not 32 bytes.
+#[derive(PartialEq, Debug, Clone)]
+pub struct PublicKey {
+ fe: FieldElement,
+}
+
+impl PartialEq<&[u8]> for PublicKey {
+ fn eq(&self, other: &&[u8]) -> bool {
+ if other.len() != PUBLIC_KEY_SIZE {
+ return false;
+ }
+ let other: [u8; 32] = (*other).try_into().unwrap();
+
+ self.fe == FieldElement::from_bytes(&other)
+ }
+}
+
+impl From<[u8; PUBLIC_KEY_SIZE]> for PublicKey {
+ #[inline]
+ fn from(bytes: [u8; PUBLIC_KEY_SIZE]) -> Self {
+ Self {
+ fe: FieldElement::from_bytes(&bytes),
+ }
+ }
+}
+
+impl_try_from_trait!(PublicKey);
+#[cfg(feature = "serde")]
+impl_serde_traits!(PublicKey, to_bytes);
+
+impl TryFrom<&PrivateKey> for PublicKey {
+ type Error = UnknownCryptoError;
+
+ fn try_from(private_key: &PrivateKey) -> Result<Self, Self::Error> {
+ // NOTE: This implementation should be identical to key_agreement() except
+ // for the check of a resulting low order point result.
+ let scalar = Scalar::from_slice(private_key.unprotected_as_bytes())?;
+
+ Ok(PublicKey::from(
+ mont_ladder(&scalar, FieldElement::from_bytes(&BASEPOINT)).as_bytes(),
+ ))
+ }
+}
+
+impl PublicKey {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from a given byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<Self, UnknownCryptoError> {
+ let slice_len = slice.len();
+
+ if slice_len != PUBLIC_KEY_SIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ Ok(Self {
+ fe: FieldElement::from_bytes(slice.try_into().unwrap()),
+ })
+ }
+
+ #[inline]
+ /// Return the length of the object.
+ pub fn len(&self) -> usize {
+ PUBLIC_KEY_SIZE
+ }
+
+ #[inline]
+ /// Return `true` if this object does not hold any data, `false` otherwise.
+ ///
+ /// __NOTE__: This method should always return `false`, since there shouldn't be a way
+ /// to create an empty instance of this object.
+ pub fn is_empty(&self) -> bool {
+ PUBLIC_KEY_SIZE == 0
+ }
+
+ #[inline]
+ /// Convert this PublicKey to its byte-representation.
+ pub fn to_bytes(&self) -> [u8; 32] {
+ self.fe.as_bytes()
+ }
+}
+
+#[allow(clippy::derive_partial_eq_without_eq)]
+// NOTE: Scalar contains a constant-time PartialEq<Scalar> impl.
+// NOTE: All newtypes impl Drop by default and Scalar has zeroizing Drop
+/// A type to represent the `PrivateKey` that X25519 uses.
+///
+/// This type holds a scalar and is used internally as such. The scalar held is decoded
+/// (a.k.a "clamped") as mandated in the [RFC](https://datatracker.ietf.org/doc/html/rfc7748#section-5).
+///
+/// # Errors:
+/// An error will be returned if:
+/// - `slice` is not 32 bytes.
+///
+/// # Panics:
+/// A panic will occur if:
+/// - Failure to generate random bytes securely.
+///
+///
+/// # Security:
+/// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+/// that the type implements.
+///
+/// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+/// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+/// is implemented in such a way that the comparison happens in constant time. Thus, users should
+/// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+/// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+/// ```rust
+/// # #[cfg(feature = "safe_api")] {
+/// use orion::hazardous::ecc::x25519::PrivateKey;
+///
+/// // Initialize a secret key with random bytes.
+/// let secret_key = PrivateKey::generate();
+///
+/// // Secure, constant-time comparison with a byte slice
+/// assert_ne!(secret_key, &[0; 32][..]);
+///
+/// // Secure, constant-time comparison with another SecretKey
+/// assert_ne!(secret_key, PrivateKey::generate());
+/// # }
+/// # Ok::<(), orion::errors::UnknownCryptoError>(())
+/// ```
+#[derive(PartialEq)]
+pub struct PrivateKey {
+ scalar: Scalar,
+}
+
+impl PartialEq<&[u8]> for PrivateKey {
+ fn eq(&self, other: &&[u8]) -> bool {
+ match Scalar::from_slice(other) {
+ Ok(other_scalar) => self.scalar == other_scalar,
+ Err(_) => false,
+ }
+ }
+}
+
+impl core::fmt::Debug for PrivateKey {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{} {{***OMITTED***}}", stringify!(PrivateKey))
+ }
+}
+
+impl From<[u8; PRIVATE_KEY_SIZE]> for PrivateKey {
+ #[inline]
+ fn from(bytes: [u8; PRIVATE_KEY_SIZE]) -> Self {
+ PrivateKey {
+ // unwrap OK due to valid len
+ scalar: Scalar::from_slice(bytes.as_ref()).unwrap(),
+ }
+ }
+}
+
+impl PrivateKey {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from a given byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ scalar: Scalar::from_slice(slice)?,
+ })
+ }
+
+ #[inline]
+ /// Return the length of the object.
+ pub fn len(&self) -> usize {
+ PRIVATE_KEY_SIZE
+ }
+
+ #[inline]
+ /// Return `true` if this object does not hold any data, `false` otherwise.
+ ///
+ /// __NOTE__: This method should always return `false`, since there shouldn't be a way
+ /// to create an empty instance of this object.
+ pub fn is_empty(&self) -> bool {
+ PRIVATE_KEY_SIZE == 0
+ }
+
+ #[inline]
+ /// Return the object as byte slice. __**Warning**__: Should not be used unless strictly
+ /// needed. This __**breaks protections**__ that the type implements.
+ pub fn unprotected_as_bytes(&self) -> &[u8] {
+ self.scalar.0.as_ref()
+ }
+
+ #[cfg(feature = "safe_api")]
+ /// Randomly generate using a CSPRNG. Not available in `no_std` context.
+ pub fn generate() -> PrivateKey {
+ let mut value = [0u8; PRIVATE_KEY_SIZE];
+ crate::util::secure_rand_bytes(&mut value).unwrap();
+
+ Self {
+ // unwrap OK due to valid len
+ scalar: Scalar::from_slice(&value).unwrap(),
+ }
+ }
+}
+
+construct_secret_key! {
+ /// A type to represent the `SharedKey` that X25519 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.
+ (SharedKey, test_shared_key, SHARED_KEY_SIZE, SHARED_KEY_SIZE)
+}
+
+impl_from_trait!(SharedKey, SHARED_KEY_SIZE);
+
+/// X25519 (Diffie-Hellman with Montgomery form of Curve25519).
+pub fn key_agreement(
+ private_key: &PrivateKey,
+ public_key: &PublicKey,
+) -> Result<SharedKey, UnknownCryptoError> {
+ let u_coord = public_key.fe;
+ let field_element = mont_ladder(&private_key.scalar, u_coord).as_bytes();
+ // High bit should be zero.
+ debug_assert_eq!(field_element[31] & 0b1000_0000u8, 0u8);
+ if secure_cmp(&field_element, &LOW_ORDER_POINT_RESULT).is_ok() {
+ return Err(UnknownCryptoError);
+ }
+
+ Ok(SharedKey::from(field_element))
+}
+
+#[cfg(test)]
+mod public {
+ use crate::hazardous::ecc::x25519::{
+ key_agreement, PrivateKey, PublicKey, SharedKey, BASEPOINT,
+ };
+
+ #[test]
+ fn test_public_key_ignores_highbit() {
+ let u = [0u8; 32];
+
+ let mut msb_zero = u;
+ msb_zero[31] &= 127u8;
+ let mut msb_one = u;
+ msb_one[31] |= 128u8;
+
+ // These should equal each-other. The high bits differ, but should be ignored.
+ assert_eq!(PublicKey::from(msb_zero), msb_one.as_ref());
+ assert_eq!(PublicKey::from(msb_zero), PublicKey::from(msb_one));
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_highbit_ignored() {
+ // RFC 7748 dictates that the MSB of final byte must be masked when receiving a field element,
+ // used for agreement (public key). We check that modifying it does not impact the result of
+ // the agreement.
+ let k = PrivateKey::generate();
+ let mut u = [0u8; 32];
+ crate::util::secure_rand_bytes(&mut u).unwrap();
+ debug_assert_ne!(u[31] & 127u8, (u[31] & 127u8) | 128u8);
+
+ let mut u_msb_zero = u;
+ u_msb_zero[31] &= 127u8;
+ let mut u_msb_one = u;
+ u_msb_one[31] |= 128u8;
+
+ // Mask bit to 0 as we do in `FieldElement::from_bytes()`.
+ let msb_zero = key_agreement(&k, &PublicKey::from(u_msb_zero)).unwrap();
+ let msb_one = key_agreement(&k, &PublicKey::from(u_msb_one)).unwrap();
+
+ assert_eq!(msb_zero, msb_one);
+ }
+
+ #[test]
+ /// Ref: https://www.ietf.org/rfc/rfc7748.html#section-5.2
+ fn test_rfc_section_5() {
+ let mut scalar = [0u8; 32];
+ let mut point = [0u8; 32];
+ let mut expected = SharedKey::from([0u8; 32]);
+
+ hex::decode_to_slice(
+ "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
+ &mut scalar,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
+ &mut point,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
+ &mut expected.value,
+ )
+ .unwrap();
+
+ let actual = key_agreement(&PrivateKey::from(scalar), &PublicKey::from(point)).unwrap();
+ assert_eq!(actual, expected);
+
+ hex::decode_to_slice(
+ "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
+ &mut scalar,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
+ &mut point,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
+ &mut expected.value,
+ )
+ .unwrap();
+
+ let actual = key_agreement(&PrivateKey::from(scalar), &PublicKey::from(point)).unwrap();
+ assert_eq!(actual, expected);
+ }
+
+ #[test]
+ /// Ref: https://www.ietf.org/rfc/rfc7748.html#section-5.2
+ fn test_rfc_section_5_iter() {
+ let mut k = BASEPOINT;
+ let mut u = BASEPOINT;
+
+ // 1 iter
+ let ret = key_agreement(&PrivateKey::from(k), &PublicKey::from(u)).unwrap();
+ u = k;
+ k = ret.value;
+
+ let mut expected = SharedKey::from([0u8; 32]);
+ hex::decode_to_slice(
+ "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
+ &mut expected.value,
+ )
+ .unwrap();
+ assert_eq!(k, expected.value, "Failed after 1 iter");
+
+ for _ in 0..999 {
+ let ret = key_agreement(&PrivateKey::from(k), &PublicKey::from(u)).unwrap();
+ u = k;
+ k = ret.value;
+ }
+
+ hex::decode_to_slice(
+ "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51",
+ &mut expected.value,
+ )
+ .unwrap();
+ assert_eq!(k, expected.value, "Failed after 1.000 iter");
+
+ /* Taking a decade...
+ for num in 0..999000 {
+ let ret = key_agreement(&PrivateKey::from(k), &PublicKey::from(u)).unwrap();
+ u = k;
+ k = ret.value;
+ }
+
+ hex::decode_to_slice(
+ "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
+ &mut expected.value,
+ )
+ .unwrap();
+ assert_eq!(k, expected.value, "Failed after 1.000.000 iter");
+ */
+ }
+
+ #[test]
+ /// Ref: https://www.ietf.org/rfc/rfc7748.html#section-6.1
+ fn test_rfc_section_6_pub_priv_basepoint() {
+ let mut alice_pub = [0u8; 32];
+ let mut alice_priv = [0u8; 32];
+
+ let mut bob_pub = [0u8; 32];
+ let mut bob_priv = [0u8; 32];
+
+ let mut shared = SharedKey::from([0u8; 32]);
+
+ hex::decode_to_slice(
+ "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
+ &mut alice_priv,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
+ &mut alice_pub,
+ )
+ .unwrap();
+ assert_eq!(
+ key_agreement(&PrivateKey::from(alice_priv), &PublicKey::from(BASEPOINT)).unwrap(),
+ PublicKey::from(alice_pub).to_bytes().as_ref()
+ );
+
+ hex::decode_to_slice(
+ "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
+ &mut bob_priv,
+ )
+ .unwrap();
+ hex::decode_to_slice(
+ "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
+ &mut bob_pub,
+ )
+ .unwrap();
+ assert_eq!(
+ key_agreement(&PrivateKey::from(bob_priv), &PublicKey::from(BASEPOINT)).unwrap(),
+ PublicKey::from(bob_pub).to_bytes().as_ref()
+ );
+
+ hex::decode_to_slice(
+ "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742",
+ &mut shared.value,
+ )
+ .unwrap();
+ assert_eq!(
+ key_agreement(&PrivateKey::from(alice_priv), &PublicKey::from(bob_pub)).unwrap(),
+ shared.value.as_ref()
+ );
+ assert_eq!(
+ key_agreement(&PrivateKey::from(bob_priv), &PublicKey::from(alice_pub)).unwrap(),
+ shared.value.as_ref()
+ );
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/blake2/blake2b.rs b/vendor/orion/src/hazardous/hash/blake2/blake2b.rs
new file mode 100644
index 0000000..877f2bb
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/blake2/blake2b.rs
@@ -0,0 +1,414 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `size`: The desired output length for the digest.
+//! - `data`: The data to be hashed.
+//! - `expected`: The expected digest when verifying.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - `size` is 0 or greater than 64.
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) bytes of data are hashed.
+//!
+//! # Security:
+//! - The recommended minimum output size is 32.
+//! - This interface only allows creating hash digest using BLAKE2b. If using a secret key is desired,
+//! please refer to the [`mac::blake2b`] module.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::blake2::blake2b::{Blake2b, Hasher};
+//!
+//! // Using the streaming interface.
+//! let mut state = Blake2b::new(64)?;
+//! state.update(b"Some data")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the `Hasher` for convenience functions.
+//! let hash_one_shot = Hasher::Blake2b512.digest(b"Some data")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: blake2b::Blake2b::update
+//! [`reset()`]: blake2b::Blake2b::reset
+//! [`finalize()`]: blake2b::Blake2b::finalize
+//! [`mac::blake2b`]: crate::hazardous::mac::blake2b
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::hash::blake2::blake2b_core;
+use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
+
+#[cfg(feature = "safe_api")]
+use std::io;
+
+construct_public! {
+ /// A type to represent the `Digest` that BLAKE2b returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `slice` is greater than 64 bytes.
+ (Digest, test_digest, 1, BLAKE2B_OUTSIZE)
+}
+
+#[derive(Debug, Clone)]
+/// BLAKE2b streaming state.
+pub struct Blake2b {
+ _state: blake2b_core::State,
+}
+
+impl Blake2b {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize a `Blake2b` struct with a given size (in bytes).
+ pub fn new(size: usize) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ _state: blake2b_core::State::_new(&[], size)?,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ 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)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a BLAKE2b digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut tmp = [0u8; BLAKE2B_OUTSIZE];
+ self._state._finalize(&mut tmp)?;
+
+ Digest::from_slice(&tmp[..self._state.size])
+ }
+}
+
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Debug, PartialEq)]
+/// Convenience functions for common BLAKE2b operations.
+pub enum Hasher {
+ /// Blake2b with `32` as `size`.
+ Blake2b256,
+ /// Blake2b with `48` as `size`.
+ Blake2b384,
+ /// Blake2b with `64` as `size`.
+ Blake2b512,
+}
+
+impl Hasher {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a digest selected by the given Blake2b variant.
+ pub fn digest(&self, data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let size: usize = match *self {
+ Hasher::Blake2b256 => 32,
+ Hasher::Blake2b384 => 48,
+ Hasher::Blake2b512 => 64,
+ };
+
+ let mut state = Blake2b::new(size)?;
+ state.update(data)?;
+ state.finalize()
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a `Blake2b` state selected by the given Blake2b variant.
+ pub fn init(&self) -> Result<Blake2b, UnknownCryptoError> {
+ match *self {
+ Hasher::Blake2b256 => Blake2b::new(32),
+ Hasher::Blake2b384 => Blake2b::new(48),
+ Hasher::Blake2b512 => Blake2b::new(64),
+ }
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: custom digest size.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::blake2::blake2b::{Blake2b, 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 = Blake2b::new(64)?; // 512-bit hash
+/// 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 Blake2b {
+ /// 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
+ /// [`Blake2b::update`](crate::hazardous::hash::blake2::blake2b::Blake2b::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(())
+ }
+}
+
+#[cfg(test)]
+mod public {
+ mod test_streaming_interface_no_key {
+ use crate::errors::UnknownCryptoError;
+ use crate::hazardous::hash::blake2::blake2b::{Blake2b, Digest};
+ use crate::hazardous::hash::blake2::blake2b_core::{
+ compare_blake2b_states, BLAKE2B_BLOCKSIZE, BLAKE2B_OUTSIZE,
+ };
+ use crate::test_framework::incremental_interface::{
+ StreamingContextConsistencyTester, TestableStreamingContext,
+ };
+
+ impl TestableStreamingContext<Digest> for Blake2b {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ self.reset()
+ }
+
+ 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> {
+ let mut ctx = Blake2b::new(BLAKE2B_OUTSIZE)?;
+ ctx.update(input)?;
+ ctx.finalize()
+ }
+
+ fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Blake2b, state_2: &Blake2b) {
+ compare_blake2b_states(&state_1._state, &state_2._state)
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Blake2b = Blake2b::new(BLAKE2B_OUTSIZE).unwrap();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Blake2b>::new(
+ initial_state,
+ BLAKE2B_BLOCKSIZE,
+ );
+ 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: Blake2b = Blake2b::new(BLAKE2B_OUTSIZE).unwrap();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Blake2b>::new(
+ initial_state,
+ BLAKE2B_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ mod test_hasher {
+ use crate::hazardous::hash::blake2::blake2b::Hasher;
+
+ #[test]
+ fn test_hasher_interface_no_panic_and_same_result() {
+ let digest_256 = Hasher::Blake2b256.digest(b"Test").unwrap();
+ let digest_384 = Hasher::Blake2b384.digest(b"Test").unwrap();
+ let digest_512 = Hasher::Blake2b512.digest(b"Test").unwrap();
+
+ assert_eq!(digest_256, Hasher::Blake2b256.digest(b"Test").unwrap());
+ assert_eq!(digest_384, Hasher::Blake2b384.digest(b"Test").unwrap());
+ assert_eq!(digest_512, Hasher::Blake2b512.digest(b"Test").unwrap());
+
+ assert_ne!(digest_256, Hasher::Blake2b256.digest(b"Wrong").unwrap());
+ assert_ne!(digest_384, Hasher::Blake2b384.digest(b"Wrong").unwrap());
+ assert_ne!(digest_512, Hasher::Blake2b512.digest(b"Wrong").unwrap());
+
+ let _state_256 = Hasher::Blake2b256.init().unwrap();
+ let _state_384 = Hasher::Blake2b384.init().unwrap();
+ let _state_512 = Hasher::Blake2b512.init().unwrap();
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Given some data, digest() should never fail in practice and should
+ /// produce the same output on a second call.
+ /// Only panics if data is unreasonably large.
+ fn prop_hasher_digest_no_panic_and_same_result(data: Vec<u8>) -> bool {
+ let d256 = Hasher::Blake2b256.digest(&data[..]).unwrap();
+ let d384 = Hasher::Blake2b384.digest(&data[..]).unwrap();
+ let d512 = Hasher::Blake2b512.digest(&data[..]).unwrap();
+
+ let d256_re = Hasher::Blake2b256.digest(&data[..]).unwrap();
+ let d384_re = Hasher::Blake2b384.digest(&data[..]).unwrap();
+ let d512_re = Hasher::Blake2b512.digest(&data[..]).unwrap();
+
+ (d256 == d256_re) && (d384 == d384_re) && (d512 == d512_re)
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Given some data, .digest() should produce the same output as when
+ /// calling with streaming state.
+ fn prop_hasher_digest_256_same_as_streaming(data: Vec<u8>) -> bool {
+ use crate::hazardous::hash::blake2::blake2b::Blake2b;
+
+ let d256 = Hasher::Blake2b256.digest(&data[..]).unwrap();
+
+ let mut state = Blake2b::new(32).unwrap();
+ state.update(&data[..]).unwrap();
+
+ d256 == state.finalize().unwrap()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Given some data, .digest() should produce the same output as when
+ /// calling with streaming state.
+ fn prop_hasher_digest_384_same_as_streaming(data: Vec<u8>) -> bool {
+ use crate::hazardous::hash::blake2::blake2b::Blake2b;
+
+ let d384 = Hasher::Blake2b384.digest(&data[..]).unwrap();
+
+ let mut state = Blake2b::new(48).unwrap();
+ state.update(&data[..]).unwrap();
+
+ d384 == state.finalize().unwrap()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Given some data, .digest() should produce the same output as when
+ /// calling with streaming state.
+ fn prop_hasher_digest_512_same_as_streaming(data: Vec<u8>) -> bool {
+ use crate::hazardous::hash::blake2::blake2b::Blake2b;
+
+ let d512 = Hasher::Blake2b512.digest(&data[..]).unwrap();
+
+ let mut state = Blake2b::new(64).unwrap();
+ state.update(&data[..]).unwrap();
+
+ d512 == state.finalize().unwrap()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Given two different data, .digest() should never produce the
+ /// same output.
+ fn prop_hasher_digest_diff_input_diff_result(data: Vec<u8>) -> bool {
+ let d256 = Hasher::Blake2b256.digest(&data[..]).unwrap();
+ let d384 = Hasher::Blake2b384.digest(&data[..]).unwrap();
+ let d512 = Hasher::Blake2b512.digest(&data[..]).unwrap();
+
+ let d256_re = Hasher::Blake2b256.digest(b"Wrong data").unwrap();
+ let d384_re = Hasher::Blake2b384.digest(b"Wrong data").unwrap();
+ let d512_re = Hasher::Blake2b512.digest(b"Wrong data").unwrap();
+
+ (d256 != d256_re) && (d384 != d384_re) && (d512 != d512_re)
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// .init() should never fail.
+ fn prop_hasher_init_no_panic() -> bool {
+ let _d256 = Hasher::Blake2b256.init().unwrap();
+ let _d384 = Hasher::Blake2b384.init().unwrap();
+ let _d512 = Hasher::Blake2b512.init().unwrap();
+
+ true
+ }
+ }
+
+ mod test_new {
+ use crate::hazardous::hash::blake2::blake2b::Blake2b;
+
+ #[test]
+ fn test_init_size() {
+ assert!(Blake2b::new(0).is_err());
+ assert!(Blake2b::new(65).is_err());
+ assert!(Blake2b::new(1).is_ok());
+ assert!(Blake2b::new(64).is_ok());
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::blake2::blake2b::Blake2b;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Blake2b::new(64).unwrap();
+ 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/blake2/mod.rs b/vendor/orion/src/hazardous/hash/blake2/mod.rs
new file mode 100644
index 0000000..c64ab5b
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/blake2/mod.rs
@@ -0,0 +1,442 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// BLAKE2b as specified in the [RFC 7693](https://tools.ietf.org/html/rfc7693).
+pub mod blake2b;
+
+pub(crate) mod blake2b_core {
+
+ /// The blocksize for the hash function BLAKE2b.
+ pub(crate) const BLAKE2B_BLOCKSIZE: usize = 128;
+ /// The maximum key size for the hash function BLAKE2b when used in keyed mode.
+ pub(crate) const BLAKE2B_KEYSIZE: usize = 64;
+ /// The maximum output size for the hash function BLAKE2b.
+ pub(crate) const BLAKE2B_OUTSIZE: usize = 64;
+
+ use crate::errors::UnknownCryptoError;
+ use crate::util::endianness::load_u64_into_le;
+ use crate::util::u64x4::U64x4;
+
+ #[allow(clippy::unreadable_literal)]
+ /// The BLAKE2b initialization vector as defined in the RFC 7693.
+ pub(crate) const IV: [U64x4; 2] = [
+ U64x4(
+ 0x6a09e667f3bcc908,
+ 0xbb67ae8584caa73b,
+ 0x3c6ef372fe94f82b,
+ 0xa54ff53a5f1d36f1,
+ ),
+ U64x4(
+ 0x510e527fade682d1,
+ 0x9b05688c2b3e6c1f,
+ 0x1f83d9abfb41bd6b,
+ 0x5be0cd19137e2179,
+ ),
+ ];
+
+ /// BLAKE2b SIGMA as defined in the RFC 7693.
+ const SIGMA: [[usize; 16]; 12] = [
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+ [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
+ [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
+ [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
+ [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
+ [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
+ [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
+ [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
+ [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
+ [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+ [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
+ ];
+
+ /// Quarter round on the BLAKE2b internal matrix.
+ macro_rules! QROUND {
+ ($v0:expr, $v1:expr, $v2:expr, $v3:expr, $s_idx:expr, $rconst1:expr, $rconst2:expr) => {
+ $v0 = $v0.wrapping_add($v1).wrapping_add($s_idx);
+ $v3 = ($v3 ^ $v0).rotate_right($rconst1);
+ $v2 = $v2.wrapping_add($v3);
+ $v1 = ($v1 ^ $v2).rotate_right($rconst2);
+ };
+ }
+
+ /// Perform a single round based on a message schedule selection.
+ macro_rules! ROUND {
+ ($v0:expr, $v1:expr, $v2:expr, $v3:expr, $s_idx:expr, $m:expr) => {
+ let s_indexed = U64x4($m[$s_idx[0]], $m[$s_idx[2]], $m[$s_idx[4]], $m[$s_idx[6]]);
+ QROUND!($v0, $v1, $v2, $v3, s_indexed, 32, 24);
+ let s_indexed = U64x4($m[$s_idx[1]], $m[$s_idx[3]], $m[$s_idx[5]], $m[$s_idx[7]]);
+ QROUND!($v0, $v1, $v2, $v3, s_indexed, 16, 63);
+
+ // Shuffle
+ $v1 = $v1.shl_1();
+ $v2 = $v2.shl_2();
+ $v3 = $v3.shl_3();
+
+ let s_indexed = U64x4(
+ $m[$s_idx[8]],
+ $m[$s_idx[10]],
+ $m[$s_idx[12]],
+ $m[$s_idx[14]],
+ );
+ QROUND!($v0, $v1, $v2, $v3, s_indexed, 32, 24);
+ let s_indexed = U64x4(
+ $m[$s_idx[9]],
+ $m[$s_idx[11]],
+ $m[$s_idx[13]],
+ $m[$s_idx[15]],
+ );
+ QROUND!($v0, $v1, $v2, $v3, s_indexed, 16, 63);
+
+ // Unshuffle
+ $v1 = $v1.shl_3();
+ $v2 = $v2.shl_2();
+ $v3 = $v3.shl_1();
+ };
+ }
+
+ #[derive(Clone)]
+ /// BLAKE2b streaming state.
+ pub(crate) struct State {
+ pub(crate) init_state: [U64x4; 2],
+ pub(crate) internal_state: [U64x4; 2],
+ pub(crate) buffer: [u8; BLAKE2B_BLOCKSIZE],
+ pub(crate) leftover: usize,
+ pub(crate) t: [u64; 2],
+ pub(crate) f: [u64; 2],
+ pub(crate) is_finalized: bool,
+ pub(crate) is_keyed: bool,
+ pub(crate) size: usize,
+ }
+
+ impl Drop for State {
+ fn drop(&mut self) {
+ use zeroize::Zeroize;
+ self.init_state.iter_mut().zeroize();
+ self.internal_state.iter_mut().zeroize();
+ self.buffer.zeroize();
+ }
+ }
+
+ impl core::fmt::Debug for State {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "State {{ init_state: [***OMITTED***], internal_state: [***OMITTED***], buffer: \
+ [***OMITTED***], leftover: {:?}, t: {:?}, f: {:?}, is_finalized: {:?}, is_keyed: \
+ {:?}, size: {:?} }}",
+ self.leftover, self.t, self.f, self.is_finalized, self.is_keyed, self.size
+ )
+ }
+ }
+
+ impl State {
+ /// Increment the internal states offset value `t`.
+ pub(crate) fn _increment_offset(&mut self, value: u64) {
+ let (res, was_overflow) = self.t[0].overflowing_add(value);
+ self.t[0] = res;
+ if was_overflow {
+ // If this panics size limit is reached.
+ self.t[1] = self.t[1].checked_add(1).unwrap();
+ }
+ }
+
+ /// The compression function f.
+ pub(crate) fn _compress_f(&mut self, data: Option<&[u8]>) {
+ let mut m_vec = [0u64; 16];
+ match data {
+ Some(bytes) => {
+ debug_assert!(bytes.len() == BLAKE2B_BLOCKSIZE);
+ load_u64_into_le(bytes, &mut m_vec);
+ }
+ None => load_u64_into_le(&self.buffer, &mut m_vec),
+ }
+
+ let mut v0 = self.internal_state[0];
+ let mut v1 = self.internal_state[1];
+ let mut v2 = IV[0];
+ let mut v3 = U64x4(
+ self.t[0] ^ IV[1].0,
+ self.t[1] ^ IV[1].1,
+ self.f[0] ^ IV[1].2,
+ self.f[1] ^ IV[1].3,
+ );
+
+ ROUND!(v0, v1, v2, v3, SIGMA[0], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[1], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[2], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[3], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[4], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[5], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[6], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[7], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[8], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[9], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[10], m_vec);
+ ROUND!(v0, v1, v2, v3, SIGMA[11], m_vec);
+
+ self.internal_state[0] ^= v0 ^ v2;
+ self.internal_state[1] ^= v1 ^ v3;
+ }
+
+ #[allow(clippy::unreadable_literal)]
+ /// Initialize a `State` struct with a given size a key and optional key.
+ /// An empty `secret_key` equals non-MAC mode.
+ pub(crate) fn _new(sk: &[u8], size: usize) -> Result<Self, UnknownCryptoError> {
+ if !(1..=BLAKE2B_OUTSIZE).contains(&size) {
+ return Err(UnknownCryptoError);
+ }
+ let is_keyed = match sk.len() {
+ 0 => false,
+ 1..=BLAKE2B_KEYSIZE => true,
+ _ => return Err(UnknownCryptoError),
+ };
+
+ let mut context = Self {
+ init_state: [U64x4::default(); 2],
+ internal_state: IV,
+ buffer: [0u8; BLAKE2B_BLOCKSIZE],
+ leftover: 0,
+ t: [0u64; 2],
+ f: [0u64; 2],
+ is_finalized: false,
+ is_keyed,
+ size,
+ };
+
+ if is_keyed {
+ context.is_keyed = true;
+ let klen = sk.len();
+ context.internal_state[0].0 ^= 0x01010000 ^ ((klen as u64) << 8) ^ (size as u64);
+ context.init_state.copy_from_slice(&context.internal_state);
+ context._update(sk)?;
+ // The state needs updating with the secret key padded to blocksize length
+ let pad = [0u8; BLAKE2B_BLOCKSIZE];
+ let rem = BLAKE2B_BLOCKSIZE - klen;
+ context._update(pad[..rem].as_ref())?;
+ } else {
+ context.internal_state[0].0 ^= 0x01010000 ^ (size as u64);
+ context.init_state.copy_from_slice(&context.internal_state);
+ }
+
+ Ok(context)
+ }
+
+ /// Reset to `_new()` state.
+ pub(crate) fn _reset(&mut self, sk: &[u8]) -> Result<(), UnknownCryptoError> {
+ // Disallow re-setting without a key if initialized with one and vice versa
+ match (sk.len(), self.is_keyed) {
+ // new with key, reset with none
+ (0, true) => return Err(UnknownCryptoError),
+ (0, false) => (),
+ // reset with key, new with none
+ (1..=BLAKE2B_KEYSIZE, false) => return Err(UnknownCryptoError),
+ (1..=BLAKE2B_KEYSIZE, true) => (),
+ (_, _) => return Err(UnknownCryptoError),
+ }
+
+ self.internal_state.copy_from_slice(&self.init_state);
+ self.buffer = [0u8; BLAKE2B_BLOCKSIZE];
+ self.leftover = 0;
+ self.t = [0u64; 2];
+ self.f = [0u64; 2];
+ self.is_finalized = false;
+
+ if self.is_keyed {
+ self._update(sk)?;
+ // The state needs updating with the secret key padded to blocksize length
+ let pad = [0u8; BLAKE2B_BLOCKSIZE];
+ let rem = BLAKE2B_BLOCKSIZE - sk.len();
+ self._update(pad[..rem].as_ref())?;
+ }
+
+ Ok(())
+ }
+
+ /// 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 <= BLAKE2B_BLOCKSIZE);
+
+ let fill = BLAKE2B_BLOCKSIZE - self.leftover;
+
+ if bytes.len() <= fill {
+ self.buffer[self.leftover..(self.leftover + bytes.len())]
+ .copy_from_slice(bytes);
+ self.leftover += bytes.len();
+ return Ok(());
+ }
+
+ self.buffer[self.leftover..(self.leftover + fill)].copy_from_slice(&bytes[..fill]);
+ self._increment_offset(BLAKE2B_BLOCKSIZE as u64);
+ self._compress_f(None);
+ self.leftover = 0;
+ bytes = &bytes[fill..];
+ }
+
+ while bytes.len() > BLAKE2B_BLOCKSIZE {
+ self._increment_offset(BLAKE2B_BLOCKSIZE as u64);
+ self._compress_f(Some(bytes[..BLAKE2B_BLOCKSIZE].as_ref()));
+ bytes = &bytes[BLAKE2B_BLOCKSIZE..];
+ }
+
+ if !bytes.is_empty() {
+ debug_assert!(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`.
+ /// NOTE: Writes the full hash (as if `self.size == BLAKE2B_OUTSIZE`) into `dest`. Must be truncated
+ /// to `self.size` later.
+ pub(crate) fn _finalize(
+ &mut self,
+ dest: &mut [u8; BLAKE2B_OUTSIZE],
+ ) -> Result<(), UnknownCryptoError> {
+ debug_assert!(self.size <= BLAKE2B_OUTSIZE);
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+
+ self.is_finalized = true;
+
+ let in_buffer_len = self.leftover;
+ self._increment_offset(in_buffer_len as u64);
+ // Mark that it is the last block of data to be processed
+ self.f[0] = !0;
+
+ for leftover_block in self.buffer.iter_mut().skip(in_buffer_len) {
+ *leftover_block = 0;
+ }
+ self._compress_f(None);
+
+ self.internal_state[0].store_into_le(dest[..32].as_mut());
+ self.internal_state[1].store_into_le(dest[32..].as_mut());
+
+ Ok(())
+ }
+ }
+
+ #[cfg(test)]
+ pub(crate) fn compare_blake2b_states(state_1: &State, state_2: &State) {
+ assert!(state_1.init_state == state_2.init_state);
+ assert!(state_1.internal_state == state_2.internal_state);
+ assert_eq!(state_1.buffer[..], state_2.buffer[..]);
+ assert_eq!(state_1.leftover, state_2.leftover);
+ assert_eq!(state_1.t, state_2.t);
+ assert_eq!(state_1.f, state_2.f);
+ assert_eq!(state_1.is_finalized, state_2.is_finalized);
+ assert_eq!(state_1.is_keyed, state_2.is_keyed);
+ assert_eq!(state_1.size, state_2.size);
+ }
+}
+
+#[cfg(test)]
+mod private {
+ use super::blake2b_core::State;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = State::_new(&[], 64).unwrap();
+ let debug = format!("{:?}", initial_state);
+ let expected = "State { init_state: [***OMITTED***], internal_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, t: [0, 0], f: [0, 0], is_finalized: false, is_keyed: false, size: 64 }";
+ assert_eq!(debug, expected);
+ }
+
+ #[test]
+ fn test_switching_keyed_modes_fails() {
+ let mut tmp = [0u8; 64];
+
+ let mut state_keyed = State::_new(&[0u8; 64], 64).unwrap();
+ state_keyed._update(b"Tests").unwrap();
+ state_keyed._finalize(&mut tmp).unwrap();
+ assert!(state_keyed._reset(&[]).is_err());
+ assert!(state_keyed._reset(&[0u8; 64]).is_ok());
+
+ let mut state = State::_new(&[], 64).unwrap();
+ state._update(b"Tests").unwrap();
+ state_keyed._finalize(&mut tmp).unwrap();
+ assert!(state._reset(&[0u8; 64]).is_err());
+ assert!(state._reset(&[]).is_ok());
+ }
+
+ mod test_increment_offset {
+ use crate::hazardous::hash::blake2::blake2b_core::{State, BLAKE2B_BLOCKSIZE, IV};
+ use crate::util::u64x4::U64x4;
+
+ #[test]
+ fn test_offset_increase_values() {
+ let mut context = State {
+ init_state: [U64x4::default(); 2],
+ internal_state: IV,
+ buffer: [0u8; BLAKE2B_BLOCKSIZE],
+ leftover: 0,
+ t: [0u64; 2],
+ f: [0u64; 2],
+ is_finalized: false,
+ is_keyed: false,
+ size: 1,
+ };
+
+ context._increment_offset(1);
+ assert_eq!(context.t, [1u64, 0u64]);
+ context._increment_offset(17);
+ assert_eq!(context.t, [18u64, 0u64]);
+ context._increment_offset(12);
+ assert_eq!(context.t, [30u64, 0u64]);
+ // Overflow
+ context._increment_offset(u64::MAX);
+ assert_eq!(context.t, [29u64, 1u64]);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_panic_on_second_overflow() {
+ let mut context = State {
+ init_state: [U64x4::default(); 2],
+ internal_state: IV,
+ buffer: [0u8; BLAKE2B_BLOCKSIZE],
+ leftover: 0,
+ t: [1u64, u64::MAX],
+ f: [0u64; 2],
+ is_finalized: false,
+ is_keyed: false,
+ size: 1,
+ };
+
+ context._increment_offset(u64::MAX);
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/mod.rs b/vendor/orion/src/hazardous/hash/mod.rs
new file mode 100644
index 0000000..01b04c2
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/mod.rs
@@ -0,0 +1,30 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// 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/mod.rs b/vendor/orion/src/hazardous/hash/sha2/mod.rs
new file mode 100644
index 0000000..cbdbb9a
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha2/mod.rs
@@ -0,0 +1,1062 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+/// SHA256 as specified in the [FIPS PUB 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
+pub mod sha256;
+
+/// SHA384 as specified in the [FIPS PUB 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
+pub mod sha384;
+
+/// SHA512 as specified in the [FIPS PUB 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
+pub mod sha512;
+
+pub(crate) mod sha2_core {
+ use crate::errors::UnknownCryptoError;
+ use core::fmt::Debug;
+ use core::marker::PhantomData;
+ use core::ops::*;
+ use zeroize::Zeroize;
+
+ /// Word used within the SHA2 internal state.
+ pub(crate) trait Word:
+ Sized
+ + BitOr<Output = Self>
+ + BitAnd<Output = Self>
+ + BitXor<Output = Self>
+ + Shr<Self>
+ + Default
+ + Div<Output = Self>
+ + From<usize>
+ + Copy
+ + Debug
+ + PartialEq<Self>
+ + Zeroize
+ {
+ const MAX: Self;
+
+ fn wrapping_add(&self, rhs: Self) -> Self;
+
+ fn overflowing_add(&self, rhs: Self) -> (Self, bool);
+
+ fn checked_add(&self, rhs: Self) -> Option<Self>;
+
+ fn checked_shl(&self, rhs: u32) -> Option<Self>;
+
+ fn rotate_right(&self, rhs: u32) -> Self;
+
+ fn one() -> Self;
+
+ fn size_of() -> usize;
+
+ fn as_be(&self, dest: &mut [u8]);
+
+ fn from_be(src: &[u8]) -> Self;
+
+ #[allow(clippy::wrong_self_convention)]
+ fn as_be_bytes(src: &[Self], dest: &mut [u8]);
+
+ fn from_be_bytes(src: &[u8], dest: &mut [Self]);
+
+ #[cfg(any(debug_assertions, test))]
+ fn less_than_or_equal(&self, rhs: Self) -> bool;
+ }
+
+ /// Trait to define a specific SHA2 variant.
+ pub(crate) trait Variant<W: Word, const N_CONSTS: usize>: Clone {
+ /// The constants as defined in FIPS 180-4.
+ const K: [W; N_CONSTS];
+
+ /// The initial hash value H(0) as defined in FIPS 180-4.
+ const H0: [W; 8];
+
+ // Because it's currently not possible to use type parameters
+ // in const expressions (see #![feature(const_evaluatable_checked)]),
+ // we can't have this trait define the blocksize or output size
+ // of the hash function, since array-sizes are defined by these.
+ // This can be accomplished once full const-generics support lands,
+ // and should remove the need for the const parameters in the state struct.
+
+ fn big_sigma_0(x: W) -> W;
+
+ fn big_sigma_1(x: W) -> W;
+
+ fn small_sigma_0(x: W) -> W;
+
+ fn small_sigma_1(x: W) -> W;
+ }
+
+ /// The Ch function as specified in FIPS 180-4 section 4.1.3.
+ fn ch<W: Word>(x: W, y: W, z: W) -> W {
+ z ^ (x & (y ^ z))
+ }
+
+ /// The Maj function as specified in FIPS 180-4 section 4.1.3.
+ fn maj<W: Word>(x: W, y: W, z: W) -> W {
+ (x & y) | (z & (x | y))
+ }
+
+ #[derive(Clone)]
+ /// Core SHA2 state.
+ pub(crate) struct State<
+ W,
+ T,
+ const BLOCKSIZE: usize,
+ const OUTSIZE: usize,
+ const N_CONSTS: usize,
+ >
+ where
+ W: Word,
+ T: Variant<W, { N_CONSTS }>,
+ {
+ _variant: PhantomData<T>,
+ pub(crate) working_state: [W; 8],
+ pub(crate) buffer: [u8; BLOCKSIZE],
+ pub(crate) leftover: usize,
+ pub(crate) message_len: [W; 2],
+ pub(crate) is_finalized: bool,
+ }
+
+ impl<
+ W: Word,
+ T: Variant<W, { N_CONSTS }>,
+ const BLOCKSIZE: usize,
+ const OUTSIZE: usize,
+ const N_CONSTS: usize,
+ > Drop for State<W, T, BLOCKSIZE, OUTSIZE, N_CONSTS>
+ {
+ fn drop(&mut self) {
+ self.working_state.iter_mut().zeroize();
+ self.buffer.iter_mut().zeroize();
+ self.message_len.iter_mut().zeroize();
+ self.leftover.zeroize();
+ self.is_finalized.zeroize();
+ }
+ }
+
+ impl<
+ W: Word,
+ T: Variant<W, { N_CONSTS }>,
+ const BLOCKSIZE: usize,
+ const OUTSIZE: usize,
+ const N_CONSTS: usize,
+ > Debug for State<W, T, BLOCKSIZE, OUTSIZE, N_CONSTS>
+ {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "State {{ working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: {:?}, \
+ message_len: {:?}, is_finalized: {:?} }}",
+ self.leftover, self.message_len, self.is_finalized
+ )
+ }
+ }
+
+ impl<
+ W: Word,
+ T: Variant<W, { N_CONSTS }>,
+ const BLOCKSIZE: usize,
+ const OUTSIZE: usize,
+ const N_CONSTS: usize,
+ > State<W, T, BLOCKSIZE, OUTSIZE, N_CONSTS>
+ {
+ /// Increment the message length during processing of data.
+ pub(crate) fn increment_mlen(&mut self, length: &W) {
+ // The checked shift checks that the right-hand side is a legal shift.
+ // The result can still overflow if length > $primitive::MAX / 8.
+ // Should be impossible for a user to trigger, because update() processes
+ // in SHA(256/384/512)_BLOCKSIZE chunks.
+ #[cfg(any(debug_assertions, test))]
+ debug_assert!(length.less_than_or_equal(W::MAX / W::from(8)));
+
+ // left-shift to get bit-sized representation of length
+ // using .unwrap() because it should not panic in practice
+ let len = length.checked_shl(3).unwrap();
+ let (res, was_overflow) = self.message_len[1].overflowing_add(len);
+ self.message_len[1] = res;
+
+ if was_overflow {
+ // If this panics size limit is reached.
+ self.message_len[0] = self.message_len[0].checked_add(W::one()).unwrap();
+ }
+ }
+
+ #[allow(clippy::many_single_char_names)]
+ #[allow(clippy::too_many_arguments)]
+ /// Message compression adopted from [mbed
+ /// TLS](https://github.com/ARMmbed/mbedtls/blob/master/library/sha512.c).
+ pub(crate) fn compress(
+ a: W,
+ b: W,
+ c: W,
+ d: &mut W,
+ e: W,
+ f: W,
+ g: W,
+ h: &mut W,
+ x: W,
+ ki: W,
+ ) {
+ let temp1 = h
+ .wrapping_add(T::big_sigma_1(e))
+ .wrapping_add(ch(e, f, g))
+ .wrapping_add(ki)
+ .wrapping_add(x);
+
+ let temp2 = T::big_sigma_0(a).wrapping_add(maj(a, b, c));
+
+ *d = d.wrapping_add(temp1);
+ *h = temp1.wrapping_add(temp2);
+ }
+
+ #[rustfmt::skip]
+ #[allow(clippy::many_single_char_names)]
+ /// Process data in `self.buffer` or optionally `data`.
+ pub(crate) fn process(&mut self, data: Option<&[u8]>) {
+ let mut w = [W::default(); N_CONSTS];
+ // If `data.is_none()` then we want to process leftover data within `self.buffer`.
+ match data {
+ Some(bytes) => {
+ debug_assert_eq!(bytes.len(), BLOCKSIZE);
+ W::from_be_bytes(bytes, &mut w[..16]);
+ }
+ None => W::from_be_bytes(&self.buffer, &mut w[..16]),
+ }
+
+ for t in 16..T::K.len() {
+ w[t] = T::small_sigma_1(w[t - 2])
+ .wrapping_add(w[t - 7])
+ .wrapping_add(T::small_sigma_0(w[t - 15]))
+ .wrapping_add(w[t - 16]);
+ }
+
+ let mut a = self.working_state[0];
+ let mut b = self.working_state[1];
+ let mut c = self.working_state[2];
+ let mut d = self.working_state[3];
+ let mut e = self.working_state[4];
+ let mut f = self.working_state[5];
+ let mut g = self.working_state[6];
+ let mut h = self.working_state[7];
+
+ let mut t = 0;
+ while t < T::K.len() {
+ Self::compress(a, b, c, &mut d, e, f, g, &mut h, w[t], T::K[t]); t += 1;
+ Self::compress(h, a, b, &mut c, d, e, f, &mut g, w[t], T::K[t]); t += 1;
+ Self::compress(g, h, a, &mut b, c, d, e, &mut f, w[t], T::K[t]); t += 1;
+ Self::compress(f, g, h, &mut a, b, c, d, &mut e, w[t], T::K[t]); t += 1;
+ Self::compress(e, f, g, &mut h, a, b, c, &mut d, w[t], T::K[t]); t += 1;
+ Self::compress(d, e, f, &mut g, h, a, b, &mut c, w[t], T::K[t]); t += 1;
+ Self::compress(c, d, e, &mut f, g, h, a, &mut b, w[t], T::K[t]); t += 1;
+ Self::compress(b, c, d, &mut e, f, g, h, &mut a, w[t], T::K[t]); t += 1;
+ }
+
+ self.working_state[0] = self.working_state[0].wrapping_add(a);
+ self.working_state[1] = self.working_state[1].wrapping_add(b);
+ self.working_state[2] = self.working_state[2].wrapping_add(c);
+ self.working_state[3] = self.working_state[3].wrapping_add(d);
+ self.working_state[4] = self.working_state[4].wrapping_add(e);
+ self.working_state[5] = self.working_state[5].wrapping_add(f);
+ self.working_state[6] = self.working_state[6].wrapping_add(g);
+ self.working_state[7] = self.working_state[7].wrapping_add(h);
+ }
+
+ /// Initialize a new state.
+ pub(crate) fn _new() -> Self {
+ Self {
+ _variant: PhantomData::<T>,
+ working_state: T::H0,
+ buffer: [0u8; BLOCKSIZE],
+ leftover: 0,
+ message_len: [W::default(); 2],
+ is_finalized: false,
+ }
+ }
+
+ /// Reset to `new()` state.
+ pub(crate) fn _reset(&mut self) {
+ self.working_state = T::H0;
+ self.buffer = [0u8; BLOCKSIZE];
+ self.leftover = 0;
+ self.message_len = [W::default(); 2];
+ 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 <= BLOCKSIZE);
+
+ let mut want = BLOCKSIZE - 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;
+ self.increment_mlen(&W::from(want));
+
+ if self.leftover < BLOCKSIZE {
+ return Ok(());
+ }
+
+ self.process(None);
+ self.leftover = 0;
+ }
+
+ while bytes.len() >= BLOCKSIZE {
+ self.process(Some(bytes[..BLOCKSIZE].as_ref()));
+ self.increment_mlen(&W::from(BLOCKSIZE));
+ bytes = &bytes[BLOCKSIZE..];
+ }
+
+ if !bytes.is_empty() {
+ debug_assert_eq!(self.leftover, 0);
+ self.buffer[..bytes.len()].copy_from_slice(bytes);
+ self.leftover = bytes.len();
+ self.increment_mlen(&W::from(bytes.len()));
+ }
+
+ Ok(())
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ // NOTE: We need to support less than OUTSIZE in HKDF through HMAC.
+ // debug_assert_eq!(dest.len(), OUTSIZE);
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+
+ self.is_finalized = true;
+ // self.leftover should not be greater than SHA(256/384/512)_BLOCKSIZE
+ // as that would have been processed in the update call
+ debug_assert!(self.leftover < BLOCKSIZE);
+ self.buffer[self.leftover] = 0x80;
+ self.leftover += 1;
+
+ for itm in self.buffer.iter_mut().skip(self.leftover) {
+ *itm = 0;
+ }
+
+ let lenpad = W::size_of();
+ // Check for available space for length padding
+ if (BLOCKSIZE - self.leftover) < lenpad * 2 {
+ self.process(None);
+ for itm in self.buffer.iter_mut().take(self.leftover) {
+ *itm = 0;
+ }
+ }
+
+ self.message_len[0]
+ .as_be(&mut self.buffer[BLOCKSIZE - (lenpad * 2)..BLOCKSIZE - lenpad]);
+ self.message_len[1].as_be(&mut self.buffer[BLOCKSIZE - lenpad..BLOCKSIZE]);
+ self.process(None);
+
+ let to_use = OUTSIZE / W::size_of();
+ W::as_be_bytes(&self.working_state[..to_use], &mut dest[..OUTSIZE]);
+
+ Ok(())
+ }
+
+ #[cfg(test)]
+ /// Compare two Sha2 state objects to check if their fields
+ /// are the same.
+ pub(crate) fn compare_state_to_other(&self, other: &Self) {
+ for idx in 0..8 {
+ assert_eq!(self.working_state[idx], other.working_state[idx]);
+ }
+ assert_eq!(self.buffer, other.buffer);
+ assert_eq!(self.leftover, other.leftover);
+ assert_eq!(self.message_len[0], other.message_len[0]);
+ assert_eq!(self.message_len[1], other.message_len[1]);
+ assert_eq!(self.is_finalized, other.is_finalized);
+ }
+ }
+}
+
+pub(crate) mod w32 {
+ use core::convert::{From, TryFrom, TryInto};
+ use core::ops::*;
+ use zeroize::Zeroize;
+
+ #[derive(Debug, PartialEq, Copy, Clone, Default)]
+ pub(crate) struct WordU32(pub(crate) u32);
+
+ impl Zeroize for WordU32 {
+ fn zeroize(&mut self) {
+ self.0.zeroize();
+ }
+ }
+
+ impl BitOr for WordU32 {
+ type Output = Self;
+
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+ }
+
+ impl BitAnd for WordU32 {
+ type Output = Self;
+
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+ }
+
+ impl BitXor for WordU32 {
+ type Output = Self;
+
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ Self(self.0 ^ rhs.0)
+ }
+ }
+
+ impl From<usize> for WordU32 {
+ fn from(value: usize) -> Self {
+ // NOTE: Should never panic
+ Self(u32::try_from(value).unwrap())
+ }
+ }
+
+ impl From<u32> for WordU32 {
+ fn from(value: u32) -> Self {
+ Self(value)
+ }
+ }
+
+ impl Div<Self> for WordU32 {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ Self(self.0 / rhs.0)
+ }
+ }
+
+ impl Shr<WordU32> for WordU32 {
+ type Output = Self;
+
+ fn shr(self, Self(rhs): Self) -> Self::Output {
+ let Self(lhs) = self;
+ Self(lhs >> rhs)
+ }
+ }
+
+ impl super::sha2_core::Word for WordU32 {
+ const MAX: Self = Self(u32::MAX);
+
+ #[inline]
+ fn wrapping_add(&self, rhs: Self) -> Self {
+ Self(self.0.wrapping_add(rhs.0))
+ }
+
+ #[inline]
+ fn overflowing_add(&self, rhs: Self) -> (Self, bool) {
+ let (res, did_overflow) = self.0.overflowing_add(rhs.0);
+
+ (Self(res), did_overflow)
+ }
+
+ #[inline]
+ fn checked_add(&self, rhs: Self) -> Option<Self> {
+ self.0.checked_add(rhs.0).map(Self)
+ }
+
+ #[inline]
+ fn checked_shl(&self, rhs: u32) -> Option<Self> {
+ self.0.checked_shl(rhs).map(Self)
+ }
+
+ #[inline]
+ fn rotate_right(&self, rhs: u32) -> Self {
+ Self(self.0.rotate_right(rhs))
+ }
+
+ #[inline]
+ fn one() -> Self {
+ Self(1u32)
+ }
+
+ #[inline]
+ fn size_of() -> usize {
+ core::mem::size_of::<u32>()
+ }
+
+ #[inline]
+ fn as_be(&self, dest: &mut [u8]) {
+ debug_assert_eq!(dest.len(), Self::size_of());
+ dest.copy_from_slice(&self.0.to_be_bytes());
+ }
+
+ #[inline]
+ fn from_be(src: &[u8]) -> Self {
+ Self(u32::from_be_bytes(src.try_into().unwrap()))
+ }
+
+ #[inline]
+ fn as_be_bytes(src: &[Self], dest: &mut [u8]) {
+ debug_assert_eq!(dest.len(), src.len() * Self::size_of());
+ for (src_elem, dst_chunk) in src.iter().zip(dest.chunks_exact_mut(Self::size_of())) {
+ src_elem.as_be(dst_chunk);
+ }
+ }
+
+ #[inline]
+ fn from_be_bytes(src: &[u8], dest: &mut [Self]) {
+ debug_assert_eq!(dest.len(), src.len() / Self::size_of());
+ for (src_chunk, dst_elem) in src.chunks_exact(Self::size_of()).zip(dest.iter_mut()) {
+ *dst_elem = Self::from_be(src_chunk);
+ }
+ }
+
+ #[cfg(any(debug_assertions, test))]
+ fn less_than_or_equal(&self, rhs: Self) -> bool {
+ self.0 <= rhs.0
+ }
+ }
+}
+
+pub(crate) mod w64 {
+ use core::convert::{From, TryFrom, TryInto};
+ use core::ops::*;
+ use zeroize::Zeroize;
+
+ #[derive(Debug, PartialEq, Copy, Clone, Default)]
+ pub(crate) struct WordU64(pub(crate) u64);
+
+ impl Zeroize for WordU64 {
+ fn zeroize(&mut self) {
+ self.0.zeroize();
+ }
+ }
+
+ impl BitOr for WordU64 {
+ type Output = Self;
+
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+ }
+
+ impl BitAnd for WordU64 {
+ type Output = Self;
+
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+ }
+
+ impl BitXor for WordU64 {
+ type Output = Self;
+
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ Self(self.0 ^ rhs.0)
+ }
+ }
+
+ impl From<usize> for WordU64 {
+ fn from(value: usize) -> Self {
+ // NOTE: Should never panic
+ Self(u64::try_from(value).unwrap())
+ }
+ }
+
+ impl From<u64> for WordU64 {
+ fn from(value: u64) -> Self {
+ Self(value)
+ }
+ }
+
+ impl Div<Self> for WordU64 {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ Self(self.0 / rhs.0)
+ }
+ }
+
+ impl Shr<WordU64> for WordU64 {
+ type Output = Self;
+
+ fn shr(self, Self(rhs): Self) -> Self::Output {
+ let Self(lhs) = self;
+ Self(lhs >> rhs)
+ }
+ }
+
+ impl super::sha2_core::Word for WordU64 {
+ const MAX: Self = Self(u64::MAX);
+
+ #[inline]
+ fn wrapping_add(&self, rhs: Self) -> Self {
+ Self(self.0.wrapping_add(rhs.0))
+ }
+
+ #[inline]
+ fn overflowing_add(&self, rhs: Self) -> (Self, bool) {
+ let (res, did_overflow) = self.0.overflowing_add(rhs.0);
+
+ (Self(res), did_overflow)
+ }
+
+ #[inline]
+ fn checked_add(&self, rhs: Self) -> Option<Self> {
+ self.0.checked_add(rhs.0).map(Self)
+ }
+
+ #[inline]
+ fn checked_shl(&self, rhs: u32) -> Option<Self> {
+ self.0.checked_shl(rhs).map(Self)
+ }
+
+ #[inline]
+ fn rotate_right(&self, rhs: u32) -> Self {
+ Self(self.0.rotate_right(rhs))
+ }
+
+ #[inline]
+ fn one() -> Self {
+ Self(1u64)
+ }
+
+ #[inline]
+ fn size_of() -> usize {
+ core::mem::size_of::<u64>()
+ }
+
+ #[inline]
+ fn as_be(&self, dest: &mut [u8]) {
+ debug_assert_eq!(dest.len(), Self::size_of());
+ dest.copy_from_slice(&self.0.to_be_bytes());
+ }
+
+ #[inline]
+ fn from_be(src: &[u8]) -> Self {
+ Self(u64::from_be_bytes(src.try_into().unwrap()))
+ }
+
+ #[inline]
+ fn as_be_bytes(src: &[Self], dest: &mut [u8]) {
+ debug_assert_eq!(dest.len(), src.len() * Self::size_of());
+ for (src_elem, dst_chunk) in src.iter().zip(dest.chunks_exact_mut(Self::size_of())) {
+ src_elem.as_be(dst_chunk);
+ }
+ }
+
+ #[inline]
+ fn from_be_bytes(src: &[u8], dest: &mut [Self]) {
+ debug_assert_eq!(dest.len(), src.len() / Self::size_of());
+ for (src_chunk, dst_elem) in src.chunks_exact(Self::size_of()).zip(dest.iter_mut()) {
+ *dst_elem = Self::from_be(src_chunk);
+ }
+ }
+
+ #[cfg(any(debug_assertions, test))]
+ fn less_than_or_equal(&self, rhs: Self) -> bool {
+ self.0 <= rhs.0
+ }
+ }
+}
+
+#[cfg(test)]
+mod test_word {
+ use super::sha2_core::Word;
+ use super::w32::WordU32;
+ use super::w64::WordU64;
+
+ #[test]
+ #[should_panic]
+ #[cfg(target_pointer_width = "64")]
+ // We can only test this on 64-bit platforms.
+ // On 32-bit platforms, due to the on-by-default #[deny(arithmetic_overflow)]
+ // this won't compile because of `(u32::MAX as usize) + 1)`, not the from call.
+ fn w32_panic_on_above_from() {
+ let _ = WordU32::from((u32::MAX as usize) + 1);
+ }
+
+ #[test]
+ #[should_panic]
+ #[cfg(target_pointer_width = "128")]
+ // See above note.
+ fn w64_panic_on_above_from() {
+ WordU64::from((u64::MAX as usize) + 1);
+ }
+
+ #[test]
+ fn equiv_max() {
+ assert_eq!(WordU32::MAX.0, u32::MAX);
+ assert_eq!(WordU64::MAX.0, u64::MAX);
+ }
+
+ #[test]
+ fn equiv_sizeof() {
+ assert_eq!(WordU32::size_of(), core::mem::size_of::<u32>());
+ assert_eq!(WordU64::size_of(), core::mem::size_of::<u64>());
+ }
+
+ #[test]
+ fn equiv_one() {
+ assert_eq!(WordU32::one(), WordU32::from(1usize));
+ assert_eq!(WordU64::one(), WordU64::from(1usize));
+ }
+
+ #[test]
+ fn equiv_default() {
+ assert_eq!(WordU32::default().0, u32::default());
+ assert_eq!(WordU64::default().0, u64::default());
+ }
+
+ #[test]
+ fn test_results_store_and_load_u32_into_be() {
+ let input_0: [WordU32; 2] = [WordU32::from(777190791u32), WordU32::from(1465409568u32)];
+ let input_1: [WordU32; 4] = [
+ WordU32::from(3418616323u32),
+ WordU32::from(2289579672u32),
+ WordU32::from(172726903u32),
+ WordU32::from(1048927929u32),
+ ];
+ let input_2: [WordU32; 6] = [
+ WordU32::from(84693101u32),
+ WordU32::from(443297962u32),
+ WordU32::from(3962861724u32),
+ WordU32::from(3081916164u32),
+ WordU32::from(4167874952u32),
+ WordU32::from(3982893227u32),
+ ];
+ let input_3: [WordU32; 8] = [
+ WordU32::from(2761719494u32),
+ WordU32::from(242571916u32),
+ WordU32::from(3097304063u32),
+ WordU32::from(3924274282u32),
+ WordU32::from(1553851098u32),
+ WordU32::from(3673278295u32),
+ WordU32::from(3531531406u32),
+ WordU32::from(2347852690u32),
+ ];
+
+ let expected_0: [u8; 8] = [46, 82, 253, 135, 87, 88, 96, 32];
+ let expected_1: [u8; 16] = [
+ 203, 195, 242, 3, 136, 120, 54, 152, 10, 75, 154, 119, 62, 133, 94, 185,
+ ];
+ let expected_2: [u8; 24] = [
+ 5, 12, 80, 109, 26, 108, 48, 170, 236, 52, 120, 156, 183, 178, 79, 4, 248, 108, 185,
+ 136, 237, 102, 32, 171,
+ ];
+ let expected_3: [u8; 32] = [
+ 164, 156, 126, 198, 14, 117, 90, 140, 184, 157, 27, 255, 233, 231, 172, 106, 92, 157,
+ 226, 218, 218, 241, 199, 87, 210, 126, 228, 142, 139, 241, 99, 146,
+ ];
+
+ let mut actual_bytes_0 = [0u8; 8];
+ let mut actual_bytes_1 = [0u8; 16];
+ let mut actual_bytes_2 = [0u8; 24];
+ let mut actual_bytes_3 = [0u8; 32];
+
+ WordU32::as_be_bytes(&input_0, &mut actual_bytes_0);
+ WordU32::as_be_bytes(&input_1, &mut actual_bytes_1);
+ WordU32::as_be_bytes(&input_2, &mut actual_bytes_2);
+ WordU32::as_be_bytes(&input_3, &mut actual_bytes_3);
+
+ assert_eq!(actual_bytes_0, expected_0);
+ assert_eq!(actual_bytes_1, expected_1);
+ assert_eq!(actual_bytes_2, expected_2);
+ assert_eq!(actual_bytes_3, expected_3);
+
+ let mut actual_nums_0 = [WordU32::default(); 2];
+ let mut actual_nums_1 = [WordU32::default(); 4];
+ let mut actual_nums_2 = [WordU32::default(); 6];
+ let mut actual_nums_3 = [WordU32::default(); 8];
+
+ WordU32::from_be_bytes(&actual_bytes_0, &mut actual_nums_0);
+ WordU32::from_be_bytes(&actual_bytes_1, &mut actual_nums_1);
+ WordU32::from_be_bytes(&actual_bytes_2, &mut actual_nums_2);
+ WordU32::from_be_bytes(&actual_bytes_3, &mut actual_nums_3);
+
+ assert_eq!(actual_nums_0, input_0);
+ assert_eq!(actual_nums_1, input_1);
+ assert_eq!(actual_nums_2, input_2);
+ assert_eq!(actual_nums_3, input_3);
+ }
+
+ #[test]
+ fn test_results_store_and_load_u64_into_be() {
+ let input_0: [WordU64; 2] = [
+ WordU64::from(588679683042986719u64),
+ WordU64::from(14213404201893491922u64),
+ ];
+ let input_1: [WordU64; 4] = [
+ WordU64::from(11866671478157678302u64),
+ WordU64::from(12365793902795026927u64),
+ WordU64::from(3777757590820648064u64),
+ WordU64::from(6594491344853184185u64),
+ ];
+ let input_2: [WordU64; 6] = [
+ WordU64::from(2101516190274184922u64),
+ WordU64::from(7904425905466803755u64),
+ WordU64::from(16590119592260157258u64),
+ WordU64::from(6043085125584392657u64),
+ WordU64::from(292831874581513482u64),
+ WordU64::from(1878340435767862001u64),
+ ];
+ let input_3: [WordU64; 8] = [
+ WordU64::from(10720360125345046831u64),
+ WordU64::from(12576204976780952869u64),
+ WordU64::from(2183760329755932840u64),
+ WordU64::from(12806242450747917237u64),
+ WordU64::from(17861362669514295908u64),
+ WordU64::from(4901620135335484985u64),
+ WordU64::from(3014680565865559727u64),
+ WordU64::from(5106077179490460734u64),
+ ];
+
+ let expected_0: [u8; 16] = [
+ 8, 43, 105, 13, 130, 68, 74, 223, 197, 64, 39, 208, 214, 231, 244, 210,
+ ];
+ let expected_1: [u8; 32] = [
+ 164, 174, 226, 214, 73, 217, 22, 222, 171, 156, 32, 9, 173, 201, 241, 239, 52, 109, 74,
+ 131, 112, 102, 116, 128, 91, 132, 86, 240, 100, 92, 174, 185,
+ ];
+ let expected_2: [u8; 48] = [
+ 29, 42, 21, 215, 59, 6, 102, 218, 109, 178, 41, 123, 72, 190, 134, 43, 230, 59, 241,
+ 222, 245, 234, 63, 74, 83, 221, 89, 231, 113, 231, 145, 209, 4, 16, 89, 9, 215, 87,
+ 197, 10, 26, 17, 52, 172, 169, 50, 34, 241,
+ ];
+ let expected_3: [u8; 64] = [
+ 148, 198, 94, 188, 47, 116, 33, 47, 174, 135, 167, 203, 119, 135, 69, 37, 30, 78, 70,
+ 115, 41, 177, 56, 168, 177, 184, 233, 168, 152, 91, 131, 181, 247, 224, 78, 182, 224,
+ 210, 138, 100, 68, 6, 13, 139, 14, 146, 222, 57, 41, 214, 76, 0, 143, 176, 182, 175,
+ 70, 220, 110, 36, 63, 65, 228, 62,
+ ];
+
+ let mut actual_bytes_0 = [0u8; 16];
+ let mut actual_bytes_1 = [0u8; 32];
+ let mut actual_bytes_2 = [0u8; 48];
+ let mut actual_bytes_3 = [0u8; 64];
+
+ WordU64::as_be_bytes(&input_0, &mut actual_bytes_0);
+ WordU64::as_be_bytes(&input_1, &mut actual_bytes_1);
+ WordU64::as_be_bytes(&input_2, &mut actual_bytes_2);
+ WordU64::as_be_bytes(&input_3, &mut actual_bytes_3);
+
+ assert_eq!(actual_bytes_0, expected_0);
+ assert_eq!(actual_bytes_1, expected_1);
+ assert_eq!(actual_bytes_2.as_ref(), expected_2.as_ref());
+ assert_eq!(actual_bytes_3.as_ref(), expected_3.as_ref());
+
+ let mut actual_nums_0 = [WordU64::default(); 2];
+ let mut actual_nums_1 = [WordU64::default(); 4];
+ let mut actual_nums_2 = [WordU64::default(); 6];
+ let mut actual_nums_3 = [WordU64::default(); 8];
+
+ WordU64::from_be_bytes(&actual_bytes_0, &mut actual_nums_0);
+ WordU64::from_be_bytes(&actual_bytes_1, &mut actual_nums_1);
+ WordU64::from_be_bytes(&actual_bytes_2, &mut actual_nums_2);
+ WordU64::from_be_bytes(&actual_bytes_3, &mut actual_nums_3);
+
+ assert_eq!(actual_nums_0, input_0);
+ assert_eq!(actual_nums_1, input_1);
+ assert_eq!(actual_nums_2, input_2);
+ assert_eq!(actual_nums_3, input_3);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod proptests {
+ use super::*;
+
+ #[quickcheck]
+ #[rustfmt::skip]
+ fn equiv_from(n: u32, m: u64) -> bool {
+ // Implicitly assume there's no panic
+ if WordU32::from(n).0 != n { return false; }
+ if WordU64::from(m).0 != m { return false; }
+
+ true
+ }
+
+ #[quickcheck]
+ #[rustfmt::skip]
+ fn equiv_ops(n1: u32, n2: u32, m1: u64, m2: u64) -> bool {
+ // WordU32
+ let w32n1 = WordU32::from(n1);
+ let w32n2 = WordU32::from(n2);
+
+ if (w32n1 | w32n2).0 != n1 | n2 { return false; }
+ if (w32n1 & w32n2).0 != n1 & n2 { return false; }
+ if (w32n1 ^ w32n2).0 != n1 ^ n2 { return false; }
+ // Test only specific values used with Shr (in sigma functions)
+ if (w32n1 >> WordU32::from(10usize)).0 != n1 >> 10 { return false; }
+ if (w32n1 >> WordU32::from(3usize)).0 != n1 >> 3 { return false; }
+ if w32n2.0 != 0 && ((w32n1 / w32n2).0 != n1 / n2) { return false }
+
+ // WordU64
+ let w64m1 = WordU64::from(m1);
+ let w64m2 = WordU64::from(m2);
+
+ if (w64m1 | w64m2).0 != m1 | m2 { return false; }
+ if (w64m1 & w64m2).0 != m1 & m2 { return false; }
+ if (w64m1 ^ w64m2).0 != m1 ^ m2 { return false; }
+ // Test only specific values used with Shr (in sigma functions)
+ if (w64m1 >> WordU64::from(7usize)).0 != m1 >> 7 { return false; }
+ if (w64m1 >> WordU64::from(6usize)).0 != m1 >> 6 { return false; }
+ if w64m2.0 != 0 && ((w64m1 / w64m2).0 != m1 / m2) { return false }
+
+ true
+ }
+
+ #[quickcheck]
+ fn equiv_wrapping_add(n1: u32, n2: u32, m1: u64, m2: u64) -> bool {
+ let w32n1 = WordU32::from(n1);
+ let w32n2 = WordU32::from(n2);
+ let ret32 = w32n1.wrapping_add(w32n2).0 == n1.wrapping_add(n2);
+
+ let w64m1 = WordU64::from(m1);
+ let w64m2 = WordU64::from(m2);
+ let ret64 = w64m1.wrapping_add(w64m2).0 == m1.wrapping_add(m2);
+
+ ret32 && ret64
+ }
+
+ #[quickcheck]
+ fn equiv_overflowing_add(n1: u32, n2: u32, m1: u64, m2: u64) -> bool {
+ let w32n1 = WordU32::from(n1);
+ let w32n2 = WordU32::from(n2);
+ let ret32: bool = match (w32n1.overflowing_add(w32n2), n1.overflowing_add(n2)) {
+ ((w32, true), (n, true)) => w32.0 == n,
+ ((w32, false), (n, false)) => w32.0 == n,
+ _ => false,
+ };
+
+ let w64m1 = WordU64::from(m1);
+ let w64m2 = WordU64::from(m2);
+ let ret64: bool = match (w64m1.overflowing_add(w64m2), m1.overflowing_add(m2)) {
+ ((w64, true), (n, true)) => w64.0 == n,
+ ((w64, false), (n, false)) => w64.0 == n,
+ _ => false,
+ };
+
+ ret32 && ret64
+ }
+
+ #[quickcheck]
+ fn equiv_checked_add(n1: u32, n2: u32, m1: u64, m2: u64) -> bool {
+ let w32n1 = WordU32::from(n1);
+ let w32n2 = WordU32::from(n2);
+ let ret32: bool = match (w32n1.checked_add(w32n2), n1.checked_add(n2)) {
+ (Some(w32), Some(n)) => w32.0 == n,
+ (None, None) => true,
+ _ => false,
+ };
+
+ let w64m1 = WordU64::from(m1);
+ let w64m2 = WordU64::from(m2);
+ let ret64: bool = match (w64m1.checked_add(w64m2), m1.checked_add(m2)) {
+ (Some(w64), Some(n)) => w64.0 == n,
+ (None, None) => true,
+ _ => false,
+ };
+
+ ret32 && ret64
+ }
+
+ #[quickcheck]
+ fn equiv_checked_shl(n: u32, m: u64, x: u32) -> bool {
+ let w32n = WordU32::from(n);
+ let ret32: bool = match (w32n.checked_shl(x), n.checked_shl(x)) {
+ (Some(w32), Some(n1)) => w32.0 == n1,
+ (None, None) => true,
+ _ => false,
+ };
+
+ let w64m = WordU64::from(m);
+ let ret64: bool = match (w64m.checked_shl(x), m.checked_shl(x)) {
+ (Some(w64), Some(n1)) => w64.0 == n1,
+ (None, None) => true,
+ _ => false,
+ };
+
+ ret32 && ret64
+ }
+
+ #[quickcheck]
+ #[rustfmt::skip]
+ fn equiv_rotate_right(n: u32, m: u64, x: u32) -> bool {
+ let w32n = WordU32::from(n);
+ let w64m = WordU64::from(m);
+
+ if w32n.rotate_right(x).0 != n.rotate_right(x) { return false; }
+ if w64m.rotate_right(x).0 != m.rotate_right(x) { return false; }
+
+ true
+ }
+
+ #[quickcheck]
+ #[rustfmt::skip]
+ fn equiv_into_from_be(n: u32, m: u64) -> bool {
+
+ let w32n = WordU32::from(n);
+ let w64m = WordU64::from(m);
+
+ let mut dest32 = [0u8; core::mem::size_of::<u32>()];
+ let mut dest64 = [0u8; core::mem::size_of::<u64>()];
+ w32n.as_be(&mut dest32);
+ w64m.as_be(&mut dest64);
+
+ if dest32 != n.to_be_bytes() { return false; }
+ if dest64 != m.to_be_bytes() { return false; }
+
+
+ if w32n.0 != u32::from_be_bytes(dest32) { return false; }
+ if w64m.0 != u64::from_be_bytes(dest64) { return false; }
+
+ true
+ }
+
+ #[cfg(debug_assertions)]
+ #[quickcheck]
+ #[rustfmt::skip]
+ /// Word::less_than_or_equal() is only used for debug_assertions.
+ fn equiv_less_than_or_equal(n1: u32, n2: u32, m1: u64, m2: u64) -> bool {
+ let w32n1 = WordU32::from(n1);
+ let w32n2 = WordU32::from(n2);
+ let w64m1 = WordU64::from(m1);
+ let w64m2 = WordU64::from(m2);
+
+ if w32n1.less_than_or_equal(w32n2) != (n1 <= n2) { return false; }
+ if w64m1.less_than_or_equal(w64m2) != (m1 <= m2) { return false; }
+
+ true
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha256.rs b/vendor/orion/src/hazardous/hash/sha2/sha256.rs
new file mode 100644
index 0000000..720d805
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha2/sha256.rs
@@ -0,0 +1,421 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^32-1) __bits__ of data are hashed.
+//!
+//! # Security:
+//! - SHA256 is vulnerable to length extension attacks.
+//!
+//! # Recommendation:
+//! - It is recommended to use [BLAKE2b] when possible.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha2::sha256::Sha256;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha256::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha256::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha256::Sha256::update
+//! [`reset()`]: sha256::Sha256::reset
+//! [`finalize()`]: sha256::Sha256::finalize
+//! [BLAKE2b]: super::blake2::blake2b
+
+use crate::errors::UnknownCryptoError;
+
+#[cfg(feature = "safe_api")]
+use std::io;
+
+/// The blocksize for the hash function SHA256.
+pub const SHA256_BLOCKSIZE: usize = 64;
+/// The output size for the hash function SHA256.
+pub const SHA256_OUTSIZE: usize = 32;
+/// The number of constants for the hash function SHA256.
+const N_CONSTS: usize = 64;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA256 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ (Digest, test_digest, SHA256_OUTSIZE, SHA256_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA256_OUTSIZE);
+
+use super::sha2_core::{State, Variant, Word};
+use super::w32::WordU32;
+
+#[derive(Clone)]
+/// SHA256 streaming state.
+pub(crate) struct V256;
+
+impl Variant<WordU32, N_CONSTS> for V256 {
+ #[rustfmt::skip]
+ #[allow(clippy::unreadable_literal)]
+ /// The SHA256 constants as defined in FIPS 180-4.
+ const K: [WordU32; N_CONSTS] = [
+ WordU32(0x428a2f98), WordU32(0x71374491), WordU32(0xb5c0fbcf), WordU32(0xe9b5dba5),
+ WordU32(0x3956c25b), WordU32(0x59f111f1), WordU32(0x923f82a4), WordU32(0xab1c5ed5),
+ WordU32(0xd807aa98), WordU32(0x12835b01), WordU32(0x243185be), WordU32(0x550c7dc3),
+ WordU32(0x72be5d74), WordU32(0x80deb1fe), WordU32(0x9bdc06a7), WordU32(0xc19bf174),
+ WordU32(0xe49b69c1), WordU32(0xefbe4786), WordU32(0x0fc19dc6), WordU32(0x240ca1cc),
+ WordU32(0x2de92c6f), WordU32(0x4a7484aa), WordU32(0x5cb0a9dc), WordU32(0x76f988da),
+ WordU32(0x983e5152), WordU32(0xa831c66d), WordU32(0xb00327c8), WordU32(0xbf597fc7),
+ WordU32(0xc6e00bf3), WordU32(0xd5a79147), WordU32(0x06ca6351), WordU32(0x14292967),
+ WordU32(0x27b70a85), WordU32(0x2e1b2138), WordU32(0x4d2c6dfc), WordU32(0x53380d13),
+ WordU32(0x650a7354), WordU32(0x766a0abb), WordU32(0x81c2c92e), WordU32(0x92722c85),
+ WordU32(0xa2bfe8a1), WordU32(0xa81a664b), WordU32(0xc24b8b70), WordU32(0xc76c51a3),
+ WordU32(0xd192e819), WordU32(0xd6990624), WordU32(0xf40e3585), WordU32(0x106aa070),
+ WordU32(0x19a4c116), WordU32(0x1e376c08), WordU32(0x2748774c), WordU32(0x34b0bcb5),
+ WordU32(0x391c0cb3), WordU32(0x4ed8aa4a), WordU32(0x5b9cca4f), WordU32(0x682e6ff3),
+ WordU32(0x748f82ee), WordU32(0x78a5636f), WordU32(0x84c87814), WordU32(0x8cc70208),
+ WordU32(0x90befffa), WordU32(0xa4506ceb), WordU32(0xbef9a3f7), WordU32(0xc67178f2),
+ ];
+
+ #[rustfmt::skip]
+ #[allow(clippy::unreadable_literal)]
+ /// The SHA256 initial hash value H(0) as defined in FIPS 180-4.
+ const H0: [WordU32; 8] = [
+ WordU32(0x6a09e667), WordU32(0xbb67ae85), WordU32(0x3c6ef372), WordU32(0xa54ff53a),
+ WordU32(0x510e527f), WordU32(0x9b05688c), WordU32(0x1f83d9ab), WordU32(0x5be0cd19),
+ ];
+
+ /// The Big Sigma 0 function as specified in FIPS 180-4 section 4.1.2.
+ fn big_sigma_0(x: WordU32) -> WordU32 {
+ (x.rotate_right(2)) ^ x.rotate_right(13) ^ x.rotate_right(22)
+ }
+
+ /// The Big Sigma 1 function as specified in FIPS 180-4 section 4.1.2.
+ fn big_sigma_1(x: WordU32) -> WordU32 {
+ (x.rotate_right(6)) ^ x.rotate_right(11) ^ x.rotate_right(25)
+ }
+
+ /// The Small Sigma 0 function as specified in FIPS 180-4 section 4.1.2.
+ fn small_sigma_0(x: WordU32) -> WordU32 {
+ (x.rotate_right(7)) ^ x.rotate_right(18) ^ (x >> WordU32(3))
+ }
+
+ /// The Small Sigma 1 function as specified in FIPS 180-4 section 4.1.2.
+ fn small_sigma_1(x: WordU32) -> WordU32 {
+ (x.rotate_right(17)) ^ x.rotate_right(19) ^ (x >> WordU32(10))
+ }
+}
+
+#[derive(Clone, Debug)]
+/// SHA256 streaming state.
+pub struct Sha256 {
+ pub(crate) _state: State<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>,
+}
+
+impl Default for Sha256 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Sha256 {
+ /// Initialize a `Sha256` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: State::<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>::_new(),
+ }
+ }
+
+ /// 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 SHA256 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA256_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA256 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+impl crate::hazardous::mac::hmac::HmacHashFunction for Sha256 {
+ /// The blocksize of the hash function.
+ const _BLOCKSIZE: usize = SHA256_BLOCKSIZE;
+
+ /// The output size of the hash function.
+ const _OUTSIZE: usize = SHA256_OUTSIZE;
+
+ /// Create a new instance of the hash function.
+ fn _new() -> Self {
+ Self::new()
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._finalize_internal(dest)
+ }
+
+ /// Compute a digest of `data` and copy it into `dest`.
+ fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx._finalize_internal(dest)
+ }
+
+ #[cfg(test)]
+ fn compare_state_to_other(&self, other: &Self) {
+ self._state.compare_state_to_other(&other._state);
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA256.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha2::sha256::{Sha256, 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 = Sha256::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 Sha256 {
+ /// 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
+ /// [`Sha256::update`](crate::hazardous::hash::sha2::sha256::Sha256::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(())
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha256::new();
+ let default = Sha256::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha256::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha256 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU32(0), WordU32(0)], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha256 {
+ 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> {
+ Sha256::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: &Sha256, state_2: &Sha256) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha256 = Sha256::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
+ initial_state,
+ SHA256_BLOCKSIZE,
+ );
+ 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: Sha256 = Sha256::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
+ initial_state,
+ SHA256_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha2::sha256::Sha256;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha256::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
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_increment_mlen {
+ use super::*;
+
+ #[test]
+ fn test_mlen_increase_values() {
+ let mut context = Sha256::default();
+
+ context._state.increment_mlen(&WordU32::from(1u32));
+ assert_eq!(context._state.message_len[0], WordU32::from(0u32));
+ assert_eq!(context._state.message_len[1], WordU32::from(8u32));
+
+ context._state.increment_mlen(&WordU32::from(17u32));
+ assert_eq!(context._state.message_len[0], WordU32::from(0u32));
+ assert_eq!(context._state.message_len[1], WordU32::from(144u32));
+
+ context._state.increment_mlen(&WordU32::from(12u32));
+ assert_eq!(context._state.message_len[0], WordU32::from(0u32));
+ assert_eq!(context._state.message_len[1], WordU32::from(240u32));
+
+ // Overflow
+ context._state.increment_mlen(&WordU32::from(u32::MAX / 8));
+ assert_eq!(context._state.message_len[0], WordU32::from(1u32));
+ assert_eq!(context._state.message_len[1], WordU32::from(232u32));
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_panic_on_second_overflow() {
+ let mut context = Sha256::default();
+ context._state.message_len = [WordU32::MAX, WordU32::from(u32::MAX - 7)];
+ // u32::MAX - 7, to leave so that the length represented
+ // in bites should overflow by exactly one.
+ context._state.increment_mlen(&WordU32::from(1u32));
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha384.rs b/vendor/orion/src/hazardous/hash/sha2/sha384.rs
new file mode 100644
index 0000000..c043051
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha2/sha384.rs
@@ -0,0 +1,403 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) __bits__ of data are hashed.
+//!
+//! # Security:
+//! - SHA384 is vulnerable to length extension attacks.
+//!
+//! # Recommendation:
+//! - It is recommended to use [BLAKE2b] when possible.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha2::sha384::Sha384;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha384::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha384::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha384::Sha384::update
+//! [`reset()`]: sha384::Sha384::reset
+//! [`finalize()`]: sha384::Sha384::finalize
+//! [BLAKE2b]: super::blake2::blake2b
+
+use crate::errors::UnknownCryptoError;
+
+#[cfg(feature = "safe_api")]
+use std::io;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA384 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 48 bytes.
+ (Digest, test_digest, SHA384_OUTSIZE, SHA384_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA384_OUTSIZE);
+
+use super::sha2_core::{State, Variant};
+use super::w64::WordU64;
+
+/// The blocksize for the hash function SHA384.
+pub const SHA384_BLOCKSIZE: usize = 128;
+/// The output size for the hash function SHA384.
+pub const SHA384_OUTSIZE: usize = 48;
+/// The number of constants for the hash function SHA384.
+const N_CONSTS: usize = 80;
+
+#[derive(Clone)]
+pub(crate) struct 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;
+
+ #[rustfmt::skip]
+ #[allow(clippy::unreadable_literal)]
+ /// The SHA384 initial hash value H(0) as defined in FIPS 180-4.
+ const H0: [WordU64; 8] = [
+ WordU64(0xcbbb9d5dc1059ed8), WordU64(0x629a292a367cd507), WordU64(0x9159015a3070dd17), WordU64(0x152fecd8f70e5939),
+ WordU64(0x67332667ffc00b31), WordU64(0x8eb44a8768581511), WordU64(0xdb0c2e0d64f98fa7), WordU64(0x47b5481dbefa4fa4),
+ ];
+
+ /// The Big Sigma 0 function as specified in FIPS 180-4 section 4.1.3.
+ fn big_sigma_0(x: WordU64) -> WordU64 {
+ super::sha512::V512::big_sigma_0(x)
+ }
+
+ /// The Big Sigma 1 function as specified in FIPS 180-4 section 4.1.3.
+ fn big_sigma_1(x: WordU64) -> WordU64 {
+ super::sha512::V512::big_sigma_1(x)
+ }
+
+ /// The Small Sigma 0 function as specified in FIPS 180-4 section 4.1.3.
+ fn small_sigma_0(x: WordU64) -> WordU64 {
+ super::sha512::V512::small_sigma_0(x)
+ }
+
+ /// The Small Sigma 1 function as specified in FIPS 180-4 section 4.1.3.
+ fn small_sigma_1(x: WordU64) -> WordU64 {
+ super::sha512::V512::small_sigma_1(x)
+ }
+}
+
+#[derive(Clone, Debug)]
+/// SHA384 streaming state.
+pub struct Sha384 {
+ pub(crate) _state: State<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>,
+}
+
+impl Default for Sha384 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Sha384 {
+ /// Initialize a `Sha384` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: State::<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>::_new(),
+ }
+ }
+
+ /// 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 SHA384 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA384_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA384 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+impl crate::hazardous::mac::hmac::HmacHashFunction for Sha384 {
+ /// The blocksize of the hash function.
+ const _BLOCKSIZE: usize = SHA384_BLOCKSIZE;
+
+ /// The output size of the hash function.
+ const _OUTSIZE: usize = SHA384_OUTSIZE;
+
+ /// Create a new instance of the hash function.
+ fn _new() -> Self {
+ Self::new()
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._finalize_internal(dest)
+ }
+
+ /// Compute a digest of `data` and copy it into `dest`.
+ fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx._finalize_internal(dest)
+ }
+
+ #[cfg(test)]
+ fn compare_state_to_other(&self, other: &Self) {
+ self._state.compare_state_to_other(&other._state);
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA384.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha2::sha384::{Sha384, 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 = Sha384::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 Sha384 {
+ /// 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
+ /// [`Sha384::update`](crate::hazardous::hash::sha2::sha384::Sha384::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(())
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha384::new();
+ let default = Sha384::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha384::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha384 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU64(0), WordU64(0)], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha384 {
+ 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> {
+ Sha384::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: &Sha384, state_2: &Sha384) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha384 = Sha384::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha384>::new(
+ initial_state,
+ SHA384_BLOCKSIZE,
+ );
+ 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: Sha384 = Sha384::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha384>::new(
+ initial_state,
+ SHA384_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha2::sha384::Sha384;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha384::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
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_increment_mlen {
+ use super::*;
+
+ #[test]
+ fn test_mlen_increase_values() {
+ let mut context = Sha384::default();
+
+ context._state.increment_mlen(&WordU64::from(1u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(8u64));
+
+ context._state.increment_mlen(&WordU64::from(17u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(144u64));
+
+ context._state.increment_mlen(&WordU64::from(12u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(240u64));
+
+ // Overflow
+ context._state.increment_mlen(&WordU64::from(u64::MAX / 8));
+ assert_eq!(context._state.message_len[0], WordU64::from(1u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(232u64));
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_panic_on_second_overflow() {
+ use crate::hazardous::hash::sha2::sha2_core::Word;
+
+ let mut context = Sha384::default();
+ context._state.message_len = [WordU64::MAX, WordU64::from(u64::MAX - 7)];
+ // u64::MAX - 7, to leave so that the length represented
+ // in bites should overflow by exactly one.
+ context._state.increment_mlen(&WordU64::from(1u64));
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha512.rs b/vendor/orion/src/hazardous/hash/sha2/sha512.rs
new file mode 100644
index 0000000..0e865c5
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha2/sha512.rs
@@ -0,0 +1,424 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) __bits__ of data are hashed.
+//!
+//! # Security:
+//! - SHA512 is vulnerable to length extension attacks.
+//!
+//! # Recommendation:
+//! - It is recommended to use [BLAKE2b] when possible.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha2::sha512::Sha512;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha512::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha512::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha512::Sha512::update
+//! [`reset()`]: sha512::Sha512::reset
+//! [`finalize()`]: sha512::Sha512::finalize
+//! [BLAKE2b]: super::blake2::blake2b
+
+use crate::errors::UnknownCryptoError;
+
+#[cfg(feature = "safe_api")]
+use std::io;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA512 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 64 bytes.
+ (Digest, test_digest, SHA512_OUTSIZE, SHA512_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA512_OUTSIZE);
+
+use super::sha2_core::{State, Variant, Word};
+use super::w64::WordU64;
+
+/// The blocksize for the hash function SHA512.
+pub const SHA512_BLOCKSIZE: usize = 128;
+/// The output size for the hash function SHA512.
+pub const SHA512_OUTSIZE: usize = 64;
+/// The number of constants for the hash function SHA512.
+const N_CONSTS: usize = 80;
+
+#[derive(Clone)]
+pub(crate) struct V512;
+
+impl Variant<WordU64, N_CONSTS> for V512 {
+ #[rustfmt::skip]
+ #[allow(clippy::unreadable_literal)]
+ /// The SHA512 constants as defined in FIPS 180-4.
+ const K: [WordU64; N_CONSTS] = [
+ WordU64(0x428a2f98d728ae22), WordU64(0x7137449123ef65cd), WordU64(0xb5c0fbcfec4d3b2f), WordU64(0xe9b5dba58189dbbc),
+ WordU64(0x3956c25bf348b538), WordU64(0x59f111f1b605d019), WordU64(0x923f82a4af194f9b), WordU64(0xab1c5ed5da6d8118),
+ WordU64(0xd807aa98a3030242), WordU64(0x12835b0145706fbe), WordU64(0x243185be4ee4b28c), WordU64(0x550c7dc3d5ffb4e2),
+ WordU64(0x72be5d74f27b896f), WordU64(0x80deb1fe3b1696b1), WordU64(0x9bdc06a725c71235), WordU64(0xc19bf174cf692694),
+ WordU64(0xe49b69c19ef14ad2), WordU64(0xefbe4786384f25e3), WordU64(0x0fc19dc68b8cd5b5), WordU64(0x240ca1cc77ac9c65),
+ WordU64(0x2de92c6f592b0275), WordU64(0x4a7484aa6ea6e483), WordU64(0x5cb0a9dcbd41fbd4), WordU64(0x76f988da831153b5),
+ WordU64(0x983e5152ee66dfab), WordU64(0xa831c66d2db43210), WordU64(0xb00327c898fb213f), WordU64(0xbf597fc7beef0ee4),
+ WordU64(0xc6e00bf33da88fc2), WordU64(0xd5a79147930aa725), WordU64(0x06ca6351e003826f), WordU64(0x142929670a0e6e70),
+ WordU64(0x27b70a8546d22ffc), WordU64(0x2e1b21385c26c926), WordU64(0x4d2c6dfc5ac42aed), WordU64(0x53380d139d95b3df),
+ WordU64(0x650a73548baf63de), WordU64(0x766a0abb3c77b2a8), WordU64(0x81c2c92e47edaee6), WordU64(0x92722c851482353b),
+ WordU64(0xa2bfe8a14cf10364), WordU64(0xa81a664bbc423001), WordU64(0xc24b8b70d0f89791), WordU64(0xc76c51a30654be30),
+ WordU64(0xd192e819d6ef5218), WordU64(0xd69906245565a910), WordU64(0xf40e35855771202a), WordU64(0x106aa07032bbd1b8),
+ WordU64(0x19a4c116b8d2d0c8), WordU64(0x1e376c085141ab53), WordU64(0x2748774cdf8eeb99), WordU64(0x34b0bcb5e19b48a8),
+ WordU64(0x391c0cb3c5c95a63), WordU64(0x4ed8aa4ae3418acb), WordU64(0x5b9cca4f7763e373), WordU64(0x682e6ff3d6b2b8a3),
+ WordU64(0x748f82ee5defb2fc), WordU64(0x78a5636f43172f60), WordU64(0x84c87814a1f0ab72), WordU64(0x8cc702081a6439ec),
+ WordU64(0x90befffa23631e28), WordU64(0xa4506cebde82bde9), WordU64(0xbef9a3f7b2c67915), WordU64(0xc67178f2e372532b),
+ WordU64(0xca273eceea26619c), WordU64(0xd186b8c721c0c207), WordU64(0xeada7dd6cde0eb1e), WordU64(0xf57d4f7fee6ed178),
+ WordU64(0x06f067aa72176fba), WordU64(0x0a637dc5a2c898a6), WordU64(0x113f9804bef90dae), WordU64(0x1b710b35131c471b),
+ WordU64(0x28db77f523047d84), WordU64(0x32caab7b40c72493), WordU64(0x3c9ebe0a15c9bebc), WordU64(0x431d67c49c100d4c),
+ WordU64(0x4cc5d4becb3e42b6), WordU64(0x597f299cfc657e2a), WordU64(0x5fcb6fab3ad6faec), WordU64(0x6c44198c4a475817),
+ ];
+
+ #[rustfmt::skip]
+ #[allow(clippy::unreadable_literal)]
+ /// The SHA512 initial hash value H(0) as defined in FIPS 180-4.
+ const H0: [WordU64; 8] = [
+ WordU64(0x6a09e667f3bcc908), WordU64(0xbb67ae8584caa73b), WordU64(0x3c6ef372fe94f82b), WordU64(0xa54ff53a5f1d36f1),
+ WordU64(0x510e527fade682d1), WordU64(0x9b05688c2b3e6c1f), WordU64(0x1f83d9abfb41bd6b), WordU64(0x5be0cd19137e2179),
+ ];
+
+ /// The Big Sigma 0 function as specified in FIPS 180-4 section 4.1.3.
+ fn big_sigma_0(x: WordU64) -> WordU64 {
+ (x.rotate_right(28)) ^ x.rotate_right(34) ^ x.rotate_right(39)
+ }
+
+ /// The Big Sigma 1 function as specified in FIPS 180-4 section 4.1.3.
+ fn big_sigma_1(x: WordU64) -> WordU64 {
+ (x.rotate_right(14)) ^ x.rotate_right(18) ^ x.rotate_right(41)
+ }
+
+ /// The Small Sigma 0 function as specified in FIPS 180-4 section 4.1.3.
+ fn small_sigma_0(x: WordU64) -> WordU64 {
+ (x.rotate_right(1)) ^ x.rotate_right(8) ^ (x >> WordU64(7))
+ }
+
+ /// The Small Sigma 1 function as specified in FIPS 180-4 section 4.1.3.
+ fn small_sigma_1(x: WordU64) -> WordU64 {
+ (x.rotate_right(19)) ^ x.rotate_right(61) ^ (x >> WordU64(6))
+ }
+}
+
+#[derive(Clone, Debug)]
+/// SHA512 streaming state.
+pub struct Sha512 {
+ pub(crate) _state: State<WordU64, V512, SHA512_BLOCKSIZE, SHA512_OUTSIZE, N_CONSTS>,
+}
+
+impl Default for Sha512 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Sha512 {
+ /// Initialize a `Sha512` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: State::<WordU64, V512, SHA512_BLOCKSIZE, SHA512_OUTSIZE, N_CONSTS>::_new(),
+ }
+ }
+
+ /// 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 SHA512 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA512_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA512 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+impl crate::hazardous::mac::hmac::HmacHashFunction for Sha512 {
+ /// The blocksize of the hash function.
+ const _BLOCKSIZE: usize = SHA512_BLOCKSIZE;
+
+ /// The output size of the hash function.
+ const _OUTSIZE: usize = SHA512_OUTSIZE;
+
+ /// Create a new instance of the hash function.
+ fn _new() -> Self {
+ Self::new()
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._finalize_internal(dest)
+ }
+
+ /// Compute a digest of `data` and copy it into `dest`.
+ fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx._finalize_internal(dest)
+ }
+
+ #[cfg(test)]
+ fn compare_state_to_other(&self, other: &Self) {
+ self._state.compare_state_to_other(&other._state);
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA512.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha2::sha512::{Sha512, 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 = Sha512::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 Sha512 {
+ /// 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
+ /// [`Sha512::update`](crate::hazardous::hash::sha2::sha512::Sha512::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(())
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha512::new();
+ let default = Sha512::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha512::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha512 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU64(0), WordU64(0)], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha512 {
+ 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> {
+ Sha512::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: &Sha512, state_2: &Sha512) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha512 = Sha512::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha512>::new(
+ initial_state,
+ SHA512_BLOCKSIZE,
+ );
+ 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: Sha512 = Sha512::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha512>::new(
+ initial_state,
+ SHA512_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha2::sha512::Sha512;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha512::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
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_increment_mlen {
+ use super::*;
+
+ #[test]
+ fn test_mlen_increase_values() {
+ let mut context = Sha512::default();
+
+ context._state.increment_mlen(&WordU64::from(1u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(8u64));
+
+ context._state.increment_mlen(&WordU64::from(17u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(144u64));
+
+ context._state.increment_mlen(&WordU64::from(12u64));
+ assert_eq!(context._state.message_len[0], WordU64::from(0u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(240u64));
+
+ // Overflow
+ context._state.increment_mlen(&WordU64::from(u64::MAX / 8));
+ assert_eq!(context._state.message_len[0], WordU64::from(1u64));
+ assert_eq!(context._state.message_len[1], WordU64::from(232u64));
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_panic_on_second_overflow() {
+ let mut context = Sha512::default();
+ context._state.message_len = [WordU64::MAX, WordU64::from(u64::MAX - 7)];
+ // u64::MAX - 7, to leave so that the length represented
+ // in bites should overflow by exactly one.
+ context._state.increment_mlen(&WordU64::from(1u64));
+ }
+ }
+}
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 0000000..28be25d
--- /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 0000000..e235f2b
--- /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 0000000..f972db9
--- /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 0000000..96ccdb3
--- /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 0000000..d1b2432
--- /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/kdf/argon2i.rs b/vendor/orion/src/hazardous/kdf/argon2i.rs
new file mode 100644
index 0000000..840c5b8
--- /dev/null
+++ b/vendor/orion/src/hazardous/kdf/argon2i.rs
@@ -0,0 +1,2607 @@
+// MIT License
+
+// Copyright (c) 2020-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:
+//! Argon2i version 1.3. This implementation is available with features `safe_api` and `alloc`.
+//!
+//! # Note:
+//! This implementation only supports a single thread/lane.
+//!
+//! # Parameters:
+//! - `expected`: The expected derived key.
+//! - `password`: Password.
+//! - `salt`: Salt value.
+//! - `iterations`: Iteration count.
+//! - `memory`: Memory size in kibibytes (KiB).
+//! - `secret`: Optional secret value used for hashing.
+//! - `ad`: Optional associated data used for hashing.
+//! - `dst_out`: Destination buffer for the derived key. The length of the
+//! derived key is implied by the length of `dst_out`.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The length of the `password` is greater than [`u32::MAX`].
+//! - The length of the `salt` is greater than [`u32::MAX`] or less than `8`.
+//! - The length of the `secret` is greater than [`u32::MAX`].
+//! - The length of the `ad` is greater than [`u32::MAX`].
+//! - The length of `dst_out` is greater than [`u32::MAX`] or less than `4`.
+//! - `iterations` is less than `1`.
+//! - `memory` is less than `8`.
+//! - The hashed password does not match the expected when verifying.
+//!
+//! # Panics:
+//! A panic will occur if:
+//!
+//! # Security:
+//! - Salts should always be generated using a CSPRNG.
+//! [`secure_rand_bytes()`] can be used for this.
+//! - The minimum recommended length for a salt is `16` bytes.
+//! - The minimum recommended length for a hashed password is `16` bytes.
+//! - The minimum recommended iteration count is `3`.
+//! - Password hashes should always be compared in constant-time.
+//! - Please note that when verifying, a copy of the computed password hash is placed into
+//! `dst_out`. If the derived hash is considered sensitive and you want to provide defense
+//! in depth against an attacker reading your application's private memory, then you as
+//! the user are responsible for zeroing out this buffer (see the [`zeroize` crate]).
+//!
+//! The cost parameters were the recommended values at time of writing. Please be sure to also check
+//! [OWASP] for the latest recommended values.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::{hazardous::kdf::argon2i, util};
+//!
+//! let mut salt = [0u8; 16];
+//! util::secure_rand_bytes(&mut salt)?;
+//! let password = b"Secret password";
+//! let mut dst_out = [0u8; 64];
+//!
+//! argon2i::derive_key(password, &salt, 3, 1<<16, None, None, &mut dst_out)?;
+//!
+//! let expected_dk = dst_out;
+//!
+//! assert!(argon2i::verify(
+//! &expected_dk,
+//! password,
+//! &salt,
+//! 3,
+//! 1<<16,
+//! None,
+//! None,
+//! &mut dst_out
+//! )
+//! .is_ok());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`secure_rand_bytes()`]: crate::util::secure_rand_bytes
+//! [`zeroize` crate]: https://crates.io/crates/zeroize
+//! [OWASP]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::hash::blake2::blake2b::Blake2b;
+use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
+use crate::util;
+use crate::util::endianness::{load_u64_into_le, store_u64_into_le};
+use zeroize::Zeroize;
+
+/// The Argon2 version (0x13).
+pub const ARGON2_VERSION: u32 = 0x13;
+
+/// The Argon2 variant (i).
+pub const ARGON2_VARIANT: u32 = 1;
+
+/// The amount of segments per lane, as defined in the spec.
+const SEGMENTS_PER_LANE: usize = 4;
+
+/// The amount of lanes supported.
+pub(crate) const LANES: u32 = 1;
+
+/// The minimum amount of memory.
+pub(crate) const MIN_MEMORY: u32 = 8 * LANES;
+
+/// The minimum amount of iterations.
+pub(crate) const MIN_ITERATIONS: u32 = 1;
+
+const fn lower_mult_add(x: u64, y: u64) -> u64 {
+ let mask = 0xFFFF_FFFFu64;
+ let x_l = x & mask;
+ let y_l = y & mask;
+ let xy = x_l.wrapping_mul(y_l);
+ x.wrapping_add(y.wrapping_add(xy.wrapping_add(xy)))
+}
+
+/// BLAKE2 G with 64-bit multiplications.
+fn g(a: &mut u64, b: &mut u64, c: &mut u64, d: &mut u64) {
+ *a = lower_mult_add(*a, *b);
+ *d = (*d ^ *a).rotate_right(32);
+ *c = lower_mult_add(*c, *d);
+ *b = (*b ^ *c).rotate_right(24);
+ *a = lower_mult_add(*a, *b);
+ *d = (*d ^ *a).rotate_right(16);
+ *c = lower_mult_add(*c, *d);
+ *b = (*b ^ *c).rotate_right(63);
+}
+
+#[allow(clippy::too_many_arguments)]
+fn permutation_p(
+ v0: &mut u64,
+ v1: &mut u64,
+ v2: &mut u64,
+ v3: &mut u64,
+ v4: &mut u64,
+ v5: &mut u64,
+ v6: &mut u64,
+ v7: &mut u64,
+ v8: &mut u64,
+ v9: &mut u64,
+ v10: &mut u64,
+ v11: &mut u64,
+ v12: &mut u64,
+ v13: &mut u64,
+ v14: &mut u64,
+ v15: &mut u64,
+) {
+ g(v0, v4, v8, v12);
+ g(v1, v5, v9, v13);
+ g(v2, v6, v10, v14);
+ g(v3, v7, v11, v15);
+ g(v0, v5, v10, v15);
+ g(v1, v6, v11, v12);
+ g(v2, v7, v8, v13);
+ g(v3, v4, v9, v14);
+}
+
+/// H0 as defined in the specification.
+fn initial_hash(
+ hash_length: u32,
+ memory_kib: u32,
+ passes: u32,
+ p: &[u8],
+ s: &[u8],
+ k: &[u8],
+ x: &[u8],
+) -> Result<[u8; 72], UnknownCryptoError> {
+ // We save additional 8 bytes in H0 for when the first two blocks are processed,
+ // so that this may contain two little-endian integers.
+ let mut h0 = [0u8; 72];
+ let mut hasher = Blake2b::new(BLAKE2B_OUTSIZE)?;
+
+ // Collect the first part to reduce times we update the hasher state.
+ h0[0..4].copy_from_slice(&LANES.to_le_bytes());
+ h0[4..8].copy_from_slice(&hash_length.to_le_bytes());
+ h0[8..12].copy_from_slice(&memory_kib.to_le_bytes());
+ h0[12..16].copy_from_slice(&passes.to_le_bytes());
+ h0[16..20].copy_from_slice(&ARGON2_VERSION.to_le_bytes());
+ h0[20..24].copy_from_slice(&ARGON2_VARIANT.to_le_bytes());
+ h0[24..28].copy_from_slice(&(p.len() as u32).to_le_bytes());
+
+ hasher.update(&h0[..28])?;
+ hasher.update(p)?;
+ hasher.update(&(s.len() as u32).to_le_bytes())?;
+ hasher.update(s)?;
+ hasher.update(&(k.len() as u32).to_le_bytes())?;
+ hasher.update(k)?;
+ hasher.update(&(x.len() as u32).to_le_bytes())?;
+ hasher.update(x)?;
+ h0[0..BLAKE2B_OUTSIZE].copy_from_slice(hasher.finalize()?.as_ref());
+
+ Ok(h0)
+}
+
+/// H' as defined in the specification.
+fn extended_hash(input: &[u8], dst: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ if dst.is_empty() {
+ return Err(UnknownCryptoError);
+ }
+
+ let outlen = dst.len() as u32;
+
+ if dst.len() <= BLAKE2B_OUTSIZE {
+ let mut ctx = Blake2b::new(dst.len())?;
+ ctx.update(&outlen.to_le_bytes())?;
+ ctx.update(input)?;
+ dst.copy_from_slice(ctx.finalize()?.as_ref());
+ } else {
+ let mut ctx = Blake2b::new(BLAKE2B_OUTSIZE)?;
+ ctx.update(&outlen.to_le_bytes())?;
+ ctx.update(input)?;
+
+ let mut tmp = ctx.finalize()?;
+ dst[..BLAKE2B_OUTSIZE].copy_from_slice(tmp.as_ref());
+
+ let mut pos = BLAKE2B_OUTSIZE / 2;
+ let mut toproduce = dst.len() - BLAKE2B_OUTSIZE / 2;
+
+ while toproduce > BLAKE2B_OUTSIZE {
+ ctx.reset()?;
+ ctx.update(tmp.as_ref())?;
+ tmp = ctx.finalize()?;
+
+ dst[pos..(pos + BLAKE2B_OUTSIZE)].copy_from_slice(tmp.as_ref());
+ pos += BLAKE2B_OUTSIZE / 2;
+ toproduce -= BLAKE2B_OUTSIZE / 2;
+ }
+
+ ctx = Blake2b::new(toproduce)?;
+ ctx.update(tmp.as_ref())?;
+ tmp = ctx.finalize()?;
+ dst[pos..outlen as usize].copy_from_slice(&tmp.as_ref()[..toproduce]);
+ }
+
+ Ok(())
+}
+
+#[rustfmt::skip]
+fn fill_block(w: &mut [u64; 128]) {
+
+ let mut v0: u64; let mut v1: u64; let mut v2: u64; let mut v3: u64;
+ let mut v4: u64; let mut v5: u64; let mut v6: u64; let mut v7: u64;
+ let mut v8: u64; let mut v9: u64; let mut v10: u64; let mut v11: u64;
+ let mut v12: u64; let mut v13: u64; let mut v14: u64; let mut v15: u64;
+
+ let mut idx = 0;
+
+ // Operate on columns.
+ while idx < 128 {
+ v0 = w[idx ]; v1 = w[idx + 1]; v2 = w[idx + 2]; v3 = w[idx + 3];
+ v4 = w[idx + 4]; v5 = w[idx + 5]; v6 = w[idx + 6]; v7 = w[idx + 7];
+ v8 = w[idx + 8]; v9 = w[idx + 9]; v10 = w[idx + 10]; v11 = w[idx + 11];
+ v12 = w[idx + 12]; v13 = w[idx + 13]; v14 = w[idx + 14]; v15 = w[idx + 15];
+
+ permutation_p(
+ &mut v0, &mut v1, &mut v2, &mut v3,
+ &mut v4, &mut v5, &mut v6, &mut v7,
+ &mut v8, &mut v9, &mut v10, &mut v11,
+ &mut v12, &mut v13, &mut v14, &mut v15
+ );
+
+ w[idx ] = v0; w[idx + 1] = v1; w[idx + 2] = v2; w[idx + 3] = v3;
+ w[idx + 4] = v4; w[idx + 5] = v5; w[idx + 6] = v6; w[idx + 7] = v7;
+ w[idx + 8] = v8; w[idx + 9] = v9; w[idx + 10] = v10; w[idx + 11] = v11;
+ w[idx + 12] = v12; w[idx + 13] = v13; w[idx + 14] = v14; w[idx + 15] = v15;
+
+ idx += 16;
+ }
+
+ idx = 0;
+ // Operate on rows.
+ while idx < 16 {
+ v0 = w[idx ]; v1 = w[idx + 1]; v2 = w[idx + 16]; v3 = w[idx + 17];
+ v4 = w[idx + 32]; v5 = w[idx + 33]; v6 = w[idx + 48]; v7 = w[idx + 49];
+ v8 = w[idx + 64]; v9 = w[idx + 65]; v10 = w[idx + 80]; v11 = w[idx + 81];
+ v12 = w[idx + 96]; v13 = w[idx + 97]; v14 = w[idx + 112]; v15 = w[idx + 113];
+
+ permutation_p(
+ &mut v0, &mut v1, &mut v2, &mut v3,
+ &mut v4, &mut v5, &mut v6, &mut v7,
+ &mut v8, &mut v9, &mut v10, &mut v11,
+ &mut v12, &mut v13, &mut v14, &mut v15
+ );
+
+ w[idx ] = v0; w[idx + 1] = v1; w[idx + 16] = v2; w[idx + 17] = v3;
+ w[idx + 32] = v4; w[idx + 33] = v5; w[idx + 48] = v6; w[idx + 49] = v7;
+ w[idx + 64] = v8; w[idx + 65] = v9; w[idx + 80] = v10; w[idx + 81] = v11;
+ w[idx + 96] = v12; w[idx + 97] = v13; w[idx + 112] = v14; w[idx + 113] = v15;
+
+ idx += 2;
+ }
+}
+
+/// Data-independent indexing.
+struct Gidx {
+ block: [u64; 128],
+ addresses: [u64; 128],
+ segment_length: u32,
+ offset: u32,
+}
+
+impl Gidx {
+ fn new(blocks: u32, passes: u32, segment_length: u32) -> Self {
+ let mut block = [0u64; 128];
+ block[1] = 0u64; // Lane number, we only support one (0u64).
+ block[3] = u64::from(blocks);
+ block[4] = u64::from(passes);
+ block[5] = u64::from(ARGON2_VARIANT); // The Argon2i variant
+
+ Self {
+ block,
+ addresses: [0u64; 128],
+ segment_length,
+ offset: 0,
+ }
+ }
+
+ fn init(&mut self, pass_n: u32, segment_n: u32, offset: u32, tmp_block: &mut [u64; 128]) {
+ self.block[0] = u64::from(pass_n);
+ self.block[2] = u64::from(segment_n);
+ self.block[6] = 0u64; // Counter
+ self.offset = offset;
+
+ self.next_addresses(tmp_block);
+
+ // The existing values in self.addresses are not read
+ // when generating a new address block. Therefor we
+ // do not have to zero it out.
+ }
+
+ fn next_addresses(&mut self, tmp_block: &mut [u64; 128]) {
+ self.block[6] += 1;
+ // G-two operation
+ tmp_block.copy_from_slice(&self.block);
+ fill_block(tmp_block);
+ xor_slices!(self.block, tmp_block);
+
+ self.addresses.copy_from_slice(tmp_block);
+ fill_block(&mut self.addresses);
+ xor_slices!(tmp_block, self.addresses);
+ }
+
+ fn get_next(&mut self, segment_idx: u32, tmp_block: &mut [u64; 128]) -> u32 {
+ // We get J1 and discard J2, as J2 is only relevant if we had more than
+ // a single lane.
+ let j1: u64 = self.addresses[self.offset as usize] & 0xFFFF_FFFFu64;
+ self.offset = (self.offset + 1) % 128; // Wrap-around on block length.
+ if self.offset == 0 {
+ self.next_addresses(tmp_block);
+ }
+
+ // The Argon2 specification for this version (1.3) does not conform
+ // to the official reference implementation. This implementation follows
+ // the reference implementation and ignores the specification where they
+ // disagree. See https://github.com/P-H-C/phc-winner-argon2/issues/183.
+
+ let n_blocks = self.block[3] as u32;
+ let pass_n = self.block[0] as u32;
+ let segment_n = self.block[2] as u32;
+
+ let ref_start_pos: u32 = if pass_n == 0 && segment_n == 0 {
+ segment_idx - 1
+ } else if pass_n == 0 {
+ segment_n * self.segment_length + segment_idx - 1
+ } else {
+ n_blocks - self.segment_length + segment_idx - 1
+ };
+
+ let mut ref_pos: u64 = (j1 * j1) >> 32;
+ ref_pos = (ref_start_pos as u64 * ref_pos) >> 32;
+ ref_pos = (ref_start_pos as u64 - 1) - ref_pos;
+
+ if pass_n == 0 || segment_n == 3 {
+ ref_pos as u32 % n_blocks
+ } else {
+ (self.segment_length * (segment_n + 1) + ref_pos as u32) % n_blocks
+ }
+ }
+}
+
+#[allow(clippy::too_many_arguments)]
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Argon2i password hashing function as described in the [P-H-C specification](https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf).
+pub fn derive_key(
+ password: &[u8],
+ salt: &[u8],
+ iterations: u32,
+ memory: u32,
+ secret: Option<&[u8]>,
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if password.len() > 0xFFFF_FFFF {
+ return Err(UnknownCryptoError);
+ }
+ if salt.len() > 0xFFFF_FFFF || salt.len() < 8 {
+ return Err(UnknownCryptoError);
+ }
+ if iterations < MIN_ITERATIONS {
+ return Err(UnknownCryptoError);
+ }
+ if memory < MIN_MEMORY {
+ return Err(UnknownCryptoError);
+ }
+
+ let k = match secret {
+ Some(n_val) => {
+ if n_val.len() > 0xFFFF_FFFF {
+ return Err(UnknownCryptoError);
+ }
+
+ n_val
+ }
+ None => &[0u8; 0],
+ };
+
+ let x = match ad {
+ Some(n_val) => {
+ if n_val.len() > 0xFFFF_FFFF {
+ return Err(UnknownCryptoError);
+ }
+
+ n_val
+ }
+ None => &[0u8; 0],
+ };
+
+ if dst_out.len() > 0xFFFF_FFFF || dst_out.len() < 4 {
+ return Err(UnknownCryptoError);
+ }
+
+ // Round down to 4 * p threads
+ let n_blocks = memory - (memory & 3);
+ // Divide by 4 (SEGMENTS_PER_LANE)
+ let segment_length = n_blocks >> 2;
+
+ let mut blocks = vec![[0u64; 128]; n_blocks as usize];
+
+ // Fill first two blocks
+ let mut h0 = initial_hash(
+ dst_out.len() as u32,
+ memory,
+ iterations,
+ password,
+ salt,
+ k,
+ x,
+ )?;
+ let mut tmp = [0u8; 1024];
+ debug_assert_eq!(
+ h0.len(),
+ ((core::mem::size_of::<u32>() * 2) + BLAKE2B_OUTSIZE)
+ );
+ debug_assert!(
+ h0[BLAKE2B_OUTSIZE..(BLAKE2B_OUTSIZE + core::mem::size_of::<u32>())]
+ == [0u8; core::mem::size_of::<u32>()]
+ ); // Block 0
+ debug_assert!(
+ h0[BLAKE2B_OUTSIZE + core::mem::size_of::<u32>()..] == [0u8; core::mem::size_of::<u32>()]
+ ); // Lane
+
+ // H' into the first two blocks
+ extended_hash(&h0, &mut tmp)?;
+ load_u64_into_le(&tmp, &mut blocks[0]);
+ h0[BLAKE2B_OUTSIZE..(BLAKE2B_OUTSIZE + core::mem::size_of::<u32>())]
+ .copy_from_slice(&1u32.to_le_bytes()); // Block 1
+ extended_hash(&h0, &mut tmp)?;
+ load_u64_into_le(&tmp, &mut blocks[1]);
+
+ let mut gidx = Gidx::new(n_blocks, iterations, segment_length);
+ let mut working_block = [0u64; 128];
+
+ for pass_n in 0..iterations as usize {
+ for segment_n in 0..SEGMENTS_PER_LANE {
+ let offset = match (pass_n, segment_n) {
+ (0, 0) => 2, // The first two blocks have already been processed
+ _ => 0,
+ };
+
+ gidx.init(pass_n as u32, segment_n as u32, offset, &mut working_block);
+
+ for segment_idx in offset..segment_length {
+ let reference_idx = gidx.get_next(segment_idx, &mut working_block);
+ let current_idx = segment_n as u32 * segment_length + segment_idx;
+ let previous_idx = if current_idx > 0 {
+ current_idx - 1
+ } else {
+ n_blocks - 1
+ };
+
+ let prev_b = blocks.get(previous_idx as usize).unwrap();
+ let ref_b = blocks.get(reference_idx as usize).unwrap();
+
+ // G-xor operation
+ for (el_tmp, (el_prev, el_ref)) in working_block
+ .iter_mut()
+ .zip(prev_b.iter().zip(ref_b.iter()))
+ {
+ *el_tmp = el_prev ^ el_ref;
+ }
+ let cur_b = blocks.get_mut(current_idx as usize).unwrap();
+ xor_slices!(working_block, cur_b);
+ fill_block(&mut working_block);
+ xor_slices!(working_block, cur_b);
+ }
+ }
+ }
+
+ store_u64_into_le(blocks.get(n_blocks as usize - 1).unwrap(), &mut tmp);
+ extended_hash(&tmp, dst_out)?;
+
+ working_block.zeroize();
+ tmp.zeroize();
+ h0.zeroize();
+ for block in blocks.iter_mut() {
+ block.zeroize();
+ }
+
+ Ok(())
+}
+
+#[allow(clippy::too_many_arguments)]
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Verify Argon2i derived key in constant time.
+pub fn verify(
+ expected: &[u8],
+ password: &[u8],
+ salt: &[u8],
+ iterations: u32,
+ memory: u32,
+ secret: Option<&[u8]>,
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ derive_key(password, salt, iterations, memory, secret, ad, dst_out)?;
+ util::secure_cmp(dst_out, expected)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_test_same_input_verify_true(
+ hlen: u32,
+ kib: u32,
+ p: Vec<u8>,
+ s: Vec<u8>,
+ k: Vec<u8>,
+ x: Vec<u8>,
+ ) -> bool {
+ let passes = 1;
+ let mem = if !(8..=4096).contains(&kib) {
+ 1024
+ } else {
+ kib
+ };
+ let salt = if s.len() < 8 { vec![37u8; 8] } else { s };
+
+ let mut dst_out = if !(4..=512).contains(&hlen) {
+ vec![0u8; 32]
+ } else {
+ vec![0u8; hlen as usize]
+ };
+
+ let mut dst_out_verify = dst_out.clone();
+ derive_key(&p, &salt, passes, mem, Some(&k), Some(&x), &mut dst_out).unwrap();
+
+ verify(
+ &dst_out,
+ &p,
+ &salt,
+ passes,
+ mem,
+ Some(&k),
+ Some(&x),
+ &mut dst_out_verify,
+ )
+ .is_ok()
+ }
+ }
+
+ mod test_derive_key {
+ use super::*;
+
+ #[test]
+ fn test_invalid_mem() {
+ // mem must be at least 8p, where p == threads (1)
+ let mut dst_out = [0u8; 32];
+ assert!(derive_key(&[], &[0u8; 8], 1, 9, None, None, &mut dst_out).is_ok());
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out).is_ok());
+ assert!(derive_key(&[], &[0u8; 8], 1, 7, None, None, &mut dst_out).is_err());
+ }
+
+ #[test]
+ fn test_invalid_passes() {
+ let mut dst_out = [0u8; 32];
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out).is_ok());
+ assert!(derive_key(&[], &[0u8; 8], 0, 8, None, None, &mut dst_out).is_err());
+ }
+
+ #[test]
+ fn test_dst_out() {
+ let mut dst_out_less = [0u8; 3];
+ let mut dst_out_exact = [0u8; 4];
+ let mut dst_out_above = [0u8; 5];
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out_less).is_err());
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out_exact).is_ok());
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out_above).is_ok());
+ }
+
+ #[test]
+ fn test_invalid_salt() {
+ let mut dst_out = [0u8; 32];
+ assert!(derive_key(&[], &[0u8; 8], 1, 8, None, None, &mut dst_out).is_ok());
+ assert!(derive_key(&[], &[0u8; 9], 1, 8, None, None, &mut dst_out).is_ok());
+ assert!(derive_key(&[], &[0u8; 7], 1, 8, None, None, &mut dst_out).is_err());
+ }
+
+ #[test]
+ fn test_some_or_none_same_result() {
+ let mut dst_one = [0u8; 32];
+ let mut dst_two = [0u8; 32];
+
+ derive_key(&[255u8; 16], &[1u8; 16], 1, 8, None, None, &mut dst_one).unwrap();
+ derive_key(
+ &[255u8; 16],
+ &[1u8; 16],
+ 1,
+ 8,
+ Some(&[]),
+ Some(&[]),
+ &mut dst_two,
+ )
+ .unwrap();
+
+ assert_eq!(dst_one, dst_two);
+ }
+
+ #[test]
+ fn test_hash_1() {
+ let mem = 4096;
+ let passes = 3;
+ let p = [
+ 191, 68, 49, 232, 45, 162, 83, 188, 177, 167, 232, 149, 172, 236, 153, 8, 237, 115,
+ 232, 128, 171, 254, 47, 84, 192, 208, 196, 121, 127, 221, 93, 126,
+ ];
+ let s = [
+ 52, 225, 42, 12, 59, 186, 118, 248, 198, 12, 16, 189, 191, 167, 211, 42, 89, 170,
+ 108, 9, 172, 4, 138, 232, 239, 58, 189, 238, 250, 33, 230, 130,
+ ];
+ let k = [
+ 124, 169, 187, 230, 55, 69, 29, 225, 228, 147, 41, 248, 255, 98, 195, 221, 202, 40,
+ 58, 17, 93, 122, 37, 57, 169, 9, 80, 64, 170, 177, 33, 89,
+ ];
+ let x = [
+ 129, 251, 22, 14, 88, 173, 198, 8, 123, 139, 94, 203, 61, 50, 174, 20, 153, 43,
+ 109, 154, 46, 8, 71, 4, 208, 83, 157, 133, 143, 171, 78, 195,
+ ];
+
+ let expected = [
+ 234, 181, 45, 90, 214, 219, 1, 146, 196, 60, 104, 29, 152, 103, 82, 77, 65, 214,
+ 212, 55, 121, 228, 57, 189, 202, 44, 100, 103, 180, 24, 125, 50,
+ ];
+
+ let mut actual = [0u8; 32];
+ derive_key(&p, &s, passes, mem, Some(&k), Some(&x), &mut actual).unwrap();
+
+ assert_eq!(expected.len(), actual.len());
+ assert_eq!(expected.as_ref(), &actual[..]);
+ }
+
+ #[test]
+ fn test_hash_2() {
+ let mem = 4096;
+ let passes = 3;
+ let p = [
+ 99, 137, 197, 238, 38, 112, 35, 125, 195, 31, 121, 180, 52, 30, 19, 20, 198, 227,
+ 198, 9, 66, 209, 130, 225, 200, 43, 50, 221, 47, 59, 169, 160, 220, 64, 54, 202,
+ 55, 244, 226, 8, 225, 183, 155, 186, 56, 162, 30, 15, 12, 176, 15, 182, 243, 175,
+ 24, 142, 80, 247, 2, 210, 208, 57, 28, 59,
+ ];
+ let s = [
+ 94, 32, 63, 147, 115, 103, 179, 120, 17, 232, 110, 157, 92, 70, 77, 157, 82, 46,
+ 79, 122, 29, 191, 104, 146, 125, 208, 48, 24, 6, 8, 94, 196, 65, 238, 136, 255,
+ 180, 172, 187, 23, 214, 55, 18, 84, 171, 217, 253, 6, 51, 89, 173, 55, 222, 190,
+ 71, 183, 135, 156, 229, 77, 67, 78, 96, 90,
+ ];
+ let k = [
+ 18, 85, 39, 122, 166, 85, 120, 191, 243, 15, 174, 215, 32, 185, 255, 88, 134, 238,
+ 227, 159, 77, 121, 149, 134, 255, 105, 240, 88, 150, 252, 94, 158,
+ ];
+ let x = [
+ 240, 249, 197, 139, 242, 216, 12, 130, 192, 73, 44, 189, 130, 17, 225, 223, 135,
+ 30, 139, 255, 164, 168, 69, 140, 216, 121, 225, 194, 107, 123, 143, 120, 30, 131,
+ 216, 196, 200, 81, 71, 203, 26, 66, 171, 118, 236, 26, 18, 105, 100, 35, 227, 184,
+ 16, 108, 224, 222, 186, 255, 32, 112, 189, 13, 151, 22,
+ ];
+
+ let expected = [
+ 233, 201, 213, 214, 244, 141, 73, 220, 67, 19, 106, 102, 181, 1, 197, 122, 20, 147,
+ 99, 245, 236, 160, 3, 213, 22, 219, 155, 217, 194, 24, 65, 204, 239, 56, 34, 160,
+ 140, 114, 3, 191, 247, 48, 64, 79, 125, 154, 52, 185, 0, 69, 102, 85, 183, 242,
+ 167, 198, 170, 1, 124, 235, 235, 3, 184, 75,
+ ];
+ let mut actual = [0u8; 64];
+ derive_key(&p, &s, passes, mem, Some(&k), Some(&x), &mut actual).unwrap();
+
+ assert_eq!(expected.len(), actual.len());
+ assert_eq!(expected.as_ref(), &actual[..]);
+ }
+
+ #[test]
+ fn test_hash_3() {
+ let mem = 4096;
+ let passes = 3;
+ let p = [
+ 175, 90, 106, 212, 141, 72, 174, 254, 80, 27, 64, 221, 238, 102, 191, 242, 3, 221,
+ 202, 111, 10, 217, 92, 143, 15, 200, 215, 210, 199, 59, 200, 59, 98, 141, 106, 228,
+ 166, 184, 5, 212, 172, 114, 32, 229, 179, 111, 227, 116, 216, 95, 164, 35, 31, 204,
+ 132, 215, 116, 156, 32, 7, 165, 15, 231, 148, 124, 95, 115, 150, 82, 168, 34, 154,
+ 52, 166, 104, 28, 207, 61, 162, 198, 228, 72, 196, 200, 228, 251, 124, 231, 44,
+ 151, 44, 44, 24, 70, 103, 169, 44, 240, 248, 75, 208, 142, 112, 36, 25, 49, 252,
+ 196, 121, 203, 74, 155, 220, 58, 89, 106, 82, 9, 177, 66, 30, 12, 245, 153, 116,
+ 72, 233, 233,
+ ];
+ let s = [
+ 205, 79, 28, 236, 67, 87, 187, 158, 25, 126, 159, 75, 129, 34, 145, 131, 219, 240,
+ 243, 73, 42, 223, 247, 12, 223, 190, 218, 212, 26, 109, 15, 151, 118, 77, 210, 18,
+ 171, 176, 224, 127, 48, 189, 216, 225, 175, 45, 205, 3, 196, 231, 185, 203, 127,
+ 210, 185, 238, 122, 197, 147, 147, 35, 231, 182, 42, 254, 104, 201, 72, 213, 122,
+ 46, 24, 21, 80, 26, 221, 252, 117, 51, 208, 107, 147, 24, 3, 72, 222, 32, 95, 20,
+ 107, 111, 47, 21, 43, 174, 153, 57, 154, 199, 208, 182, 89, 36, 91, 111, 117, 1,
+ 254, 254, 178, 239, 204, 146, 170, 34, 121, 126, 143, 63, 88, 94, 7, 155, 2, 126,
+ 79, 43, 183,
+ ];
+ let k = [
+ 196, 222, 200, 1, 157, 90, 55, 246, 173, 195, 253, 212, 118, 186, 31, 189, 35, 154,
+ 202, 137, 60, 32, 56, 89, 179, 44, 105, 140, 185, 225, 111, 242,
+ ];
+ let x = [
+ 28, 43, 133, 219, 80, 24, 121, 131, 89, 41, 81, 230, 215, 79, 73, 60, 59, 206, 46,
+ 22, 241, 113, 205, 178, 219, 91, 159, 220, 225, 106, 152, 3, 187, 167, 148, 23,
+ 143, 89, 43, 253, 188, 87, 150, 154, 249, 44, 189, 0, 77, 237, 69, 112, 56, 71,
+ 131, 235, 63, 141, 7, 202, 20, 247, 110, 221, 28, 72, 38, 209, 210, 171, 163, 51,
+ 42, 6, 54, 121, 208, 125, 160, 105, 81, 196, 237, 22, 206, 140, 35, 89, 160, 102,
+ 214, 22, 105, 14, 113, 54, 96, 33, 68, 149, 253, 82, 1, 222, 90, 224, 99, 228, 219,
+ 230, 5, 103, 235, 206, 183, 230, 163, 177, 51, 187, 200, 207, 244, 203, 197, 56,
+ 24, 132,
+ ];
+
+ let expected = [
+ 37, 212, 93, 127, 114, 22, 107, 220, 94, 83, 173, 159, 101, 143, 232, 110, 49, 192,
+ 93, 236, 251, 92, 209, 91, 145, 162, 48, 21, 140, 49, 59, 155, 48, 116, 129, 197,
+ 223, 12, 34, 240, 209, 200, 152, 9, 112, 175, 206, 35, 166, 229, 230, 13, 110, 89,
+ 211, 60, 28, 174, 248, 142, 43, 38, 87, 72, 175, 177, 244, 186, 81, 55, 111, 238,
+ 151, 206, 243, 145, 247, 255, 50, 126, 9, 250, 28, 80, 194, 144, 17, 173, 42, 222,
+ 251, 125, 11, 130, 169, 17, 17, 112, 45, 66, 129, 118, 96, 67, 36, 252, 61, 156,
+ 239, 121, 204, 210, 74, 162, 220, 212, 33, 239, 201, 77, 80, 231, 7, 238, 92, 151,
+ 51, 17,
+ ];
+
+ let mut actual = [0u8; 128];
+ derive_key(&p, &s, passes, mem, Some(&k), Some(&x), &mut actual).unwrap();
+
+ assert_eq!(expected.len(), actual.len());
+ assert_eq!(expected.as_ref(), &actual[..]);
+ }
+
+ #[test]
+ fn test_hash_4() {
+ let mem = 4096;
+ let passes = 3;
+ let p = [
+ 129, 27, 156, 146, 197, 105, 114, 238, 251, 207, 14, 230, 59, 139, 249, 192, 99,
+ 228, 195, 63, 0, 133, 24, 243, 246, 198, 53, 3, 56, 81, 225, 43, 229, 192, 145, 23,
+ 31, 111, 106, 70, 77, 118, 182, 116, 107, 49, 237, 149, 237, 163, 136, 12, 26, 73,
+ 70, 124, 87, 238, 250, 1, 79, 136, 101, 184, 173, 23, 79, 182, 171, 60, 249, 231,
+ 55, 169, 114, 44, 73, 163, 82, 190, 186, 224, 86, 18, 155, 129, 29, 86, 213, 238,
+ 217, 185, 25, 14, 86, 107, 104, 223, 89, 78, 168, 29, 96, 209, 116, 35, 224, 208,
+ 249, 106, 161, 58, 220, 236, 76, 142, 67, 235, 10, 79, 209, 49, 147, 59, 187, 0,
+ 18, 203, 124, 97, 30, 250, 208, 228, 93, 42, 161, 54, 172, 53, 64, 220, 141, 140,
+ 161, 12, 106, 225, 212, 66, 79, 117, 83, 228, 213, 194, 217, 90, 0, 197, 115, 31,
+ 194, 40, 215, 247, 45, 20, 15, 65, 9, 78, 108, 186, 76, 167, 18, 87, 214, 202, 31,
+ 135, 80, 188, 133, 219, 64, 254, 24, 181, 113, 154, 229, 62, 54, 242, 236, 71, 202,
+ 79, 233, 195, 46, 255, 10, 166, 193, 79, 211, 11, 85, 250, 191, 92, 94, 191, 85,
+ 219, 133, 33, 211, 134, 90, 88, 239, 179, 167, 199, 154, 163, 213, 214, 63, 25,
+ 245, 75, 237, 2, 76, 240, 56, 155, 153, 53, 241, 72, 250, 129, 121, 139, 205, 112,
+ 38, 137, 12, 8,
+ ];
+ let s = [
+ 189, 41, 181, 148, 99, 179, 60, 75, 245, 112, 106, 213, 213, 78, 183, 229, 167, 54,
+ 98, 246, 27, 90, 214, 60, 178, 63, 130, 229, 150, 254, 141, 126, 99, 182, 108, 217,
+ 134, 102, 245, 53, 136, 72, 159, 194, 239, 7, 238, 82, 96, 198, 218, 50, 80, 3,
+ 234, 33, 18, 68, 33, 114, 146, 158, 129, 148, 38, 200, 203, 26, 163, 3, 46, 76,
+ 141, 41, 14, 106, 169, 246, 216, 25, 125, 226, 110, 78, 183, 228, 119, 135, 186,
+ 151, 117, 32, 220, 221, 54, 19, 142, 73, 92, 167, 191, 28, 46, 244, 171, 254, 80,
+ 251, 245, 135, 148, 32, 167, 118, 151, 129, 27, 197, 127, 77, 165, 130, 56, 189,
+ 43, 69, 150, 27, 166, 224, 79, 44, 145, 144, 163, 83, 176, 39, 103, 199, 175, 234,
+ 30, 202, 87, 229, 38, 238, 61, 9, 82, 247, 136, 122, 94, 157, 110, 58, 198, 137,
+ 47, 238, 207, 72, 178, 225, 197, 37, 45, 139, 121, 24, 49, 202, 119, 58, 127, 2,
+ 109, 214, 104, 16, 2, 118, 238, 109, 206, 208, 105, 101, 145, 146, 152, 239, 176,
+ 59, 32, 224, 220, 231, 135, 11, 173, 222, 65, 154, 206, 130, 164, 243, 113, 40, 33,
+ 208, 85, 166, 3, 134, 139, 104, 204, 181, 43, 192, 24, 70, 249, 128, 94, 185, 217,
+ 163, 133, 2, 112, 38, 117, 159, 48, 145, 46, 194, 177, 73, 43, 108, 158, 195, 228,
+ 32, 122, 21, 185, 109, 107, 235,
+ ];
+ let k = [
+ 85, 248, 24, 79, 146, 124, 133, 99, 94, 108, 110, 97, 217, 184, 249, 109, 60, 209,
+ 248, 195, 45, 90, 90, 31, 61, 11, 202, 90, 122, 99, 155, 197,
+ ];
+ let x = [
+ 42, 203, 81, 203, 86, 170, 17, 4, 219, 64, 68, 44, 196, 213, 234, 193, 172, 102,
+ 173, 159, 41, 0, 43, 6, 149, 224, 135, 50, 224, 63, 104, 211, 226, 97, 11, 219, 95,
+ 46, 246, 231, 106, 107, 221, 60, 113, 107, 119, 53, 177, 70, 45, 54, 229, 165, 118,
+ 165, 87, 246, 180, 84, 90, 75, 122, 29, 147, 148, 250, 64, 189, 116, 238, 40, 35,
+ 228, 126, 242, 39, 64, 153, 67, 166, 8, 197, 0, 36, 189, 182, 171, 85, 202, 134,
+ 251, 73, 198, 32, 243, 17, 51, 239, 5, 100, 88, 35, 137, 190, 170, 158, 48, 45,
+ 144, 215, 173, 199, 235, 124, 133, 131, 117, 181, 211, 16, 124, 171, 174, 113, 189,
+ 79, 86, 86, 103, 223, 47, 167, 97, 85, 219, 224, 70, 160, 214, 45, 85, 249, 70,
+ 166, 179, 174, 53, 174, 127, 132, 238, 203, 238, 154, 25, 149, 102, 132, 183, 44,
+ 71, 238, 155, 158, 135, 193, 80, 115, 115, 38, 80, 161, 117, 145, 68, 48, 158, 125,
+ 12, 23, 230, 66, 143, 9, 29, 122, 105, 105, 103, 222, 157, 230, 253, 56, 188, 160,
+ 180, 244, 77, 192, 167, 145, 100, 140, 9, 55, 255, 39, 122, 191, 81, 78, 76, 97,
+ 170, 20, 225, 82, 151, 167, 79, 180, 95, 192, 237, 104, 20, 168, 187, 3, 157, 113,
+ 108, 20, 129, 179, 182, 239, 33, 192, 233, 57, 79, 242, 63, 207, 107, 10, 1, 133,
+ 169, 50, 67, 2, 20,
+ ];
+
+ let expected = [
+ 66, 170, 191, 26, 194, 179, 196, 87, 184, 52, 195, 197, 179, 30, 53, 59, 193, 138,
+ 103, 175, 140, 92, 232, 252, 74, 138, 32, 61, 249, 50, 22, 21, 255, 149, 219, 8,
+ 135, 72, 210, 76, 172, 168, 105, 16, 114, 201, 98, 51, 31, 15, 34, 201, 58, 82,
+ 248, 74, 12, 163, 190, 155, 249, 214, 49, 124, 196, 163, 177, 21, 11, 245, 119, 68,
+ 25, 68, 220, 169, 209, 151, 123, 16, 68, 236, 2, 145, 31, 230, 80, 203, 181, 208,
+ 154, 193, 185, 161, 139, 253, 142, 158, 211, 17, 205, 62, 195, 202, 115, 58, 110,
+ 253, 249, 59, 148, 61, 35, 18, 199, 60, 183, 188, 61, 102, 89, 109, 93, 51, 144,
+ 254, 84, 43, 217, 203, 232, 229, 123, 126, 171, 240, 179, 26, 168, 1, 146, 13, 161,
+ 128, 175, 209, 18, 166, 95, 107, 19, 91, 221, 120, 44, 40, 114, 159, 77, 133, 150,
+ 167, 85, 46, 10, 201, 2, 41, 28, 60, 189, 129, 116, 97, 231, 174, 105, 202, 90,
+ 227, 99, 3, 239, 102, 175, 241, 246, 111, 20, 76, 96, 252, 49, 31, 226, 225, 33,
+ 118, 1, 227, 171, 251, 231, 104, 159, 60, 217, 69, 178, 226, 175, 194, 100, 77,
+ 160, 38, 180, 65, 210, 156, 230, 242, 61, 72, 64, 65, 1, 59, 77, 131, 196, 18, 59,
+ 219, 33, 159, 18, 207, 113, 249, 21, 237, 79, 143, 180, 104, 61, 84, 238, 234, 254,
+ 33, 84, 70, 106, 244,
+ ];
+
+ let mut actual = [0u8; 256];
+ derive_key(&p, &s, passes, mem, Some(&k), Some(&x), &mut actual).unwrap();
+
+ assert_eq!(expected.len(), actual.len());
+ assert_eq!(expected.as_ref(), &actual[..]);
+ }
+
+ #[test]
+ fn test_hash_5() {
+ let mem = 4096;
+ let passes = 3;
+ let p = [
+ 48, 115, 86, 156, 252, 145, 208, 204, 187, 108, 23, 254, 163, 172, 29, 63, 200,
+ 218, 50, 100, 108, 23, 64, 12, 70, 88, 171, 112, 154, 113, 39, 238, 202, 1, 88,
+ 147, 37, 107, 10, 31, 179, 27, 92, 14, 196, 104, 92, 134, 193, 139, 207, 9, 4, 60,
+ 7, 81, 23, 63, 171, 175, 164, 40, 126, 187, 45, 142, 34, 221, 118, 39, 70, 201,
+ 192, 241, 70, 225, 70, 112, 42, 222, 151, 125, 218, 98, 246, 67, 244, 154, 9, 237,
+ 126, 152, 110, 229, 124, 125, 242, 180, 209, 57, 227, 101, 104, 128, 72, 95, 143,
+ 255, 15, 246, 59, 191, 21, 242, 102, 45, 158, 170, 38, 138, 151, 96, 199, 37, 26,
+ 240, 239, 52, 72, 23, 227, 111, 157, 80, 241, 7, 73, 150, 22, 251, 118, 3, 99, 216,
+ 139, 212, 53, 49, 51, 90, 49, 81, 252, 45, 91, 36, 32, 51, 65, 121, 67, 100, 22,
+ 106, 0, 250, 134, 118, 175, 81, 210, 93, 102, 18, 56, 161, 24, 81, 168, 37, 19, 44,
+ 23, 94, 50, 190, 77, 186, 144, 2, 97, 168, 59, 210, 183, 220, 168, 176, 112, 134,
+ 53, 57, 152, 213, 67, 14, 132, 125, 107, 212, 159, 249, 206, 89, 161, 221, 113,
+ 123, 173, 79, 11, 25, 247, 8, 208, 96, 247, 45, 163, 85, 223, 174, 123, 136, 7, 67,
+ 73, 204, 18, 235, 182, 27, 237, 32, 106, 215, 84, 253, 72, 224, 37, 146, 199, 157,
+ 238, 24, 11, 57, 191, 82, 93, 51, 131, 134, 101, 253, 177, 57, 219, 202, 246, 40,
+ 92, 241, 123, 92, 136, 66, 230, 22, 145, 181, 111, 90, 248, 45, 156, 88, 25, 49,
+ 234, 64, 117, 242, 70, 210, 242, 68, 88, 62, 76, 110, 113, 119, 57, 77, 254, 242,
+ 13, 109, 141, 252, 21, 74, 255, 128, 136, 114, 249, 161, 81, 99, 18, 54, 206, 139,
+ 220, 212, 126, 31, 188, 199, 221, 177, 222, 24, 11, 234, 84, 66, 99, 5, 56, 0, 79,
+ 134, 97, 79, 229, 69, 153, 211, 190, 88, 116, 198, 81, 194, 196, 21, 158, 99, 140,
+ 227, 97, 24, 81, 134, 32, 214, 196, 25, 134, 73, 51, 83, 59, 200, 2, 176, 180, 5,
+ 133, 104, 255, 103, 95, 109, 184, 156, 56, 239, 186, 58, 148, 102, 108, 90, 51, 57,
+ 96, 134, 15, 128, 114, 165, 104, 175, 221, 223, 255, 83, 245, 19, 205, 169, 107,
+ 179, 200, 235, 143, 104, 111, 85, 129, 124, 237, 173, 154, 227, 14, 37, 200, 62,
+ 100, 236, 219, 189, 203, 164, 255, 58, 190, 226, 160, 117, 211, 77, 213, 22, 163,
+ 231, 226, 61, 168, 11, 207, 27, 105, 153, 210, 41, 175, 83, 204, 116, 63, 118, 196,
+ 142, 210, 51, 199, 180, 211, 24, 169, 214, 119, 253, 6, 233, 137, 117, 144, 104,
+ 97, 173, 92, 31, 15, 52, 70, 8, 52, 248, 95, 89, 134, 165, 114, 164, 9, 140, 228,
+ 127, 147, 6, 189, 126, 89, 0,
+ ];
+ let s = [
+ 175, 218, 81, 18, 191, 80, 114, 142, 79, 149, 196, 40, 61, 237, 245, 255, 115, 78,
+ 114, 250, 187, 148, 98, 141, 118, 42, 225, 26, 129, 64, 145, 107, 127, 227, 222,
+ 164, 224, 187, 120, 123, 82, 13, 29, 239, 137, 26, 225, 201, 211, 142, 105, 59,
+ 240, 206, 95, 8, 15, 98, 116, 188, 68, 173, 97, 64, 84, 229, 153, 58, 169, 24, 147,
+ 143, 156, 194, 247, 47, 192, 230, 102, 39, 18, 219, 243, 23, 195, 26, 121, 231,
+ 204, 221, 38, 53, 236, 178, 142, 161, 197, 214, 232, 125, 202, 12, 26, 255, 214,
+ 113, 49, 152, 193, 111, 63, 59, 84, 243, 89, 42, 129, 194, 30, 181, 222, 12, 229,
+ 105, 129, 216, 133, 22, 16, 118, 48, 16, 162, 99, 198, 79, 136, 91, 141, 231, 47,
+ 70, 107, 60, 175, 168, 139, 254, 60, 208, 8, 135, 122, 141, 83, 141, 58, 153, 235,
+ 116, 228, 158, 165, 178, 105, 172, 197, 232, 152, 250, 201, 20, 39, 235, 175, 245,
+ 128, 47, 134, 96, 163, 176, 67, 254, 36, 219, 14, 134, 118, 17, 4, 106, 74, 201,
+ 15, 208, 179, 255, 1, 53, 229, 86, 204, 187, 183, 214, 213, 77, 100, 79, 22, 31,
+ 32, 200, 134, 95, 123, 10, 74, 99, 143, 115, 183, 50, 153, 131, 247, 204, 250, 82,
+ 141, 68, 229, 102, 2, 120, 196, 65, 221, 234, 189, 11, 141, 183, 162, 153, 144, 22,
+ 190, 24, 131, 14, 125, 143, 217, 191, 11, 185, 43, 224, 156, 114, 144, 103, 183,
+ 122, 174, 3, 139, 218, 82, 248, 7, 20, 19, 150, 226, 139, 224, 226, 181, 64, 112,
+ 193, 61, 54, 52, 219, 75, 19, 217, 109, 37, 2, 172, 53, 230, 31, 153, 5, 113, 154,
+ 9, 176, 101, 122, 199, 1, 179, 62, 250, 113, 134, 226, 204, 209, 78, 80, 14, 231,
+ 115, 245, 22, 221, 99, 131, 237, 163, 133, 13, 143, 246, 57, 1, 230, 128, 225, 97,
+ 210, 48, 181, 3, 151, 220, 97, 231, 138, 89, 136, 201, 184, 203, 18, 32, 141, 62,
+ 53, 24, 84, 142, 194, 78, 77, 155, 200, 117, 57, 12, 4, 78, 206, 16, 122, 90, 156,
+ 132, 17, 2, 83, 74, 249, 94, 242, 142, 96, 25, 226, 125, 142, 93, 223, 178, 180,
+ 232, 177, 70, 188, 31, 19, 165, 200, 137, 173, 96, 189, 242, 149, 118, 100, 142,
+ 45, 48, 239, 14, 210, 153, 120, 243, 250, 237, 151, 244, 143, 130, 114, 0, 52, 34,
+ 156, 186, 3, 145, 55, 219, 153, 37, 73, 204, 152, 228, 69, 64, 42, 209, 161, 121,
+ 66, 85, 251, 62, 127, 18, 193, 91, 187, 198, 52, 12, 88, 125, 52, 93, 135, 60, 65,
+ 176, 103, 32, 24, 108, 28, 172, 208, 106, 84, 230, 191, 240, 235, 21, 180, 14, 22,
+ 226, 41, 15, 198, 31, 98, 184, 111, 194, 206, 72, 115, 98, 135, 90, 27, 111, 64,
+ 87, 149, 20, 154, 158, 65, 172, 116, 134, 62, 49,
+ ];
+ let k = [
+ 231, 130, 29, 148, 24, 187, 24, 64, 111, 18, 54, 133, 243, 193, 55, 21, 180, 71,
+ 147, 96, 46, 96, 27, 198, 81, 167, 14, 201, 18, 221, 209, 3,
+ ];
+ let x = [
+ 241, 250, 184, 87, 167, 198, 131, 217, 47, 151, 247, 42, 139, 44, 27, 46, 227, 157,
+ 35, 46, 215, 150, 10, 236, 127, 16, 142, 203, 182, 135, 242, 203, 243, 219, 210,
+ 228, 68, 226, 135, 113, 103, 156, 13, 125, 236, 30, 50, 85, 116, 112, 221, 90, 99,
+ 197, 166, 167, 75, 140, 23, 140, 225, 186, 188, 116, 10, 59, 9, 145, 252, 193, 138,
+ 60, 148, 23, 88, 37, 213, 11, 124, 170, 22, 155, 13, 86, 84, 167, 182, 185, 59,
+ 215, 9, 101, 166, 218, 167, 180, 85, 238, 121, 226, 60, 99, 244, 94, 6, 47, 189,
+ 187, 132, 52, 37, 171, 40, 11, 159, 54, 0, 85, 196, 198, 11, 168, 68, 50, 135, 88,
+ 174, 37, 226, 249, 208, 26, 224, 55, 18, 65, 152, 215, 67, 57, 128, 226, 201, 13,
+ 45, 193, 25, 30, 39, 155, 170, 54, 53, 57, 73, 72, 18, 134, 34, 223, 24, 6, 198,
+ 224, 191, 23, 53, 230, 137, 1, 184, 167, 147, 217, 203, 119, 105, 100, 19, 161,
+ 209, 67, 192, 50, 31, 163, 108, 161, 163, 42, 11, 167, 24, 37, 163, 23, 51, 180,
+ 57, 81, 179, 163, 177, 150, 61, 23, 86, 112, 149, 38, 57, 127, 175, 214, 34, 94,
+ 206, 91, 129, 84, 179, 45, 106, 198, 26, 6, 213, 217, 217, 71, 232, 51, 85, 106, 6,
+ 220, 10, 78, 252, 221, 124, 23, 192, 247, 186, 93, 190, 89, 222, 57, 186, 228, 5,
+ 103, 88, 144, 54, 68, 190, 154, 231, 192, 228, 156, 254, 182, 145, 101, 224, 19,
+ 174, 125, 54, 41, 6, 254, 215, 86, 143, 110, 102, 102, 214, 229, 39, 184, 230, 183,
+ 220, 190, 193, 8, 26, 246, 76, 248, 100, 253, 211, 109, 108, 137, 52, 87, 88, 53,
+ 87, 154, 76, 204, 101, 215, 166, 231, 226, 65, 155, 149, 74, 171, 157, 82, 238,
+ 228, 244, 103, 203, 243, 75, 221, 193, 215, 186, 144, 67, 151, 5, 174, 208, 182,
+ 22, 195, 177, 197, 180, 177, 202, 144, 94, 109, 204, 3, 118, 42, 109, 131, 132,
+ 153, 125, 156, 34, 18, 128, 113, 176, 42, 240, 51, 173, 116, 185, 67, 229, 11, 53,
+ 237, 113, 79, 166, 83, 70, 87, 83, 182, 134, 155, 206, 42, 13, 190, 19, 169, 71,
+ 79, 33, 112, 204, 133, 147, 135, 243, 0, 90, 105, 191, 5, 154, 124, 50, 157, 209,
+ 55, 254, 97, 182, 112, 86, 107, 176, 2, 46, 11, 93, 205, 91, 146, 132, 202, 84,
+ 196, 222, 54, 223, 182, 158, 96, 66, 248, 177, 68, 203, 168, 166, 230, 105, 215,
+ 27, 75, 250, 125, 183, 10, 225, 35, 91, 250, 239, 63, 136, 87, 133, 192, 93, 122,
+ 47, 187, 224, 158, 91, 98, 70, 36, 230, 124, 189, 55, 198, 157, 53, 140, 103, 170,
+ 240, 100, 55, 41, 34, 221, 122, 66, 123, 249, 127, 15, 140, 198, 215, 70, 228, 206,
+ 186, 195, 4, 220, 116, 198, 105, 148, 180, 170, 148, 116,
+ ];
+
+ let expected = [
+ 57, 19, 91, 31, 121, 43, 175, 236, 30, 7, 247, 16, 69, 126, 137, 153, 113, 234, 23,
+ 97, 150, 124, 223, 248, 115, 179, 95, 64, 213, 230, 124, 203, 217, 56, 219, 160,
+ 56, 132, 249, 133, 214, 67, 197, 155, 191, 40, 151, 201, 159, 212, 144, 214, 71,
+ 146, 35, 223, 132, 164, 58, 22, 211, 23, 198, 155, 6, 152, 106, 65, 18, 81, 242,
+ 37, 252, 95, 118, 37, 65, 153, 138, 204, 143, 110, 17, 149, 12, 181, 31, 56, 173,
+ 194, 11, 65, 23, 10, 190, 66, 126, 4, 180, 53, 80, 65, 81, 140, 226, 22, 50, 16,
+ 182, 110, 126, 152, 180, 34, 60, 0, 19, 89, 211, 20, 199, 102, 60, 51, 106, 172,
+ 255, 153, 227, 230, 107, 180, 3, 181, 112, 128, 87, 67, 252, 193, 97, 171, 40, 115,
+ 8, 228, 234, 132, 33, 140, 206, 109, 98, 92, 221, 145, 164, 32, 190, 163, 23, 102,
+ 177, 230, 109, 207, 143, 42, 83, 119, 60, 13, 225, 155, 93, 147, 2, 163, 242, 241,
+ 41, 206, 124, 10, 150, 68, 57, 173, 120, 181, 81, 235, 237, 200, 27, 43, 118, 174,
+ 171, 238, 143, 242, 198, 247, 247, 114, 93, 187, 75, 165, 107, 88, 15, 245, 112,
+ 141, 204, 143, 46, 173, 190, 35, 190, 71, 126, 60, 61, 104, 62, 34, 71, 136, 236,
+ 67, 99, 112, 67, 145, 97, 15, 96, 18, 134, 192, 51, 62, 242, 195, 35, 85, 225, 155,
+ 139, 245, 129, 74, 86, 56, 18, 147, 222, 210, 152, 228, 252, 47, 227, 165, 109,
+ 106, 107, 163, 181, 34, 44, 226, 205, 34, 24, 99, 104, 226, 47, 70, 188, 9, 201,
+ 162, 100, 147, 24, 117, 134, 197, 169, 141, 211, 46, 77, 141, 158, 10, 126, 83,
+ 187, 199, 111, 227, 211, 154, 34, 14, 128, 200, 197, 76, 12, 230, 30, 24, 58, 74,
+ 116, 125, 80, 220, 174, 62, 204, 98, 242, 181, 67, 222, 84, 111, 35, 45, 236, 214,
+ 143, 204, 65, 47, 187, 8, 236, 100, 47, 32, 28, 171, 35, 14, 35, 96, 16, 6, 177,
+ 177, 147, 174, 180, 174, 62, 164, 232, 189, 144, 191, 209, 253, 85, 40, 205, 138,
+ 90, 53, 246, 29, 136, 145, 212, 151, 13, 13, 118, 73, 229, 134, 115, 103, 233, 93,
+ 82, 173, 51, 9, 183, 98, 70, 89, 40, 154, 252, 136, 206, 247, 190, 49, 64, 87, 236,
+ 209, 65, 10, 37, 0, 28, 8, 155, 45, 243, 53, 199, 96, 112, 25, 234, 128, 199, 95,
+ 172, 41, 141, 217, 151, 15, 124, 96, 18, 59, 33, 251, 34, 138, 60, 139, 137, 181,
+ 50, 111, 95, 247, 22, 110, 172, 112, 224, 130, 202, 215, 119, 211, 86, 59, 235,
+ 150, 55, 16, 193, 77, 240, 73, 101, 184, 57, 92, 0, 230, 186, 103, 43, 155, 225,
+ 210, 152, 28, 120, 138, 185, 242, 198, 18, 74, 140, 245, 130, 112, 217, 148, 129,
+ 224, 142, 214, 25, 81, 9, 42, 248, 39, 148,
+ ];
+ let mut actual = [0u8; 512];
+ derive_key(&p, &s, passes, mem, Some(&k), Some(&x), &mut actual).unwrap();
+
+ assert_eq!(expected.len(), actual.len());
+ assert_eq!(expected.as_ref(), &actual[..]);
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_initial_hash {
+ use super::*;
+
+ #[test]
+ fn initial_hash_test_1() {
+ let hlen = 3496473570;
+ let kib = 113001741;
+ let passes = 172774226;
+ let p = [
+ 225, 168, 40, 211, 31, 67, 71, 99, 229, 168, 106, 43, 101, 94, 51, 219, 193, 88,
+ 66, 234, 43, 144, 40, 25, 24, 168, 113, 144, 211, 83, 61, 103,
+ ];
+ let s = [
+ 123, 165, 225, 133, 80, 117, 28, 160, 138, 80, 59, 206, 190, 36, 171, 53, 127, 145,
+ 92, 208, 96, 218, 248, 198, 48, 23, 84, 226, 55, 30, 3, 81,
+ ];
+ let k = [
+ 235, 154, 1, 51, 161, 180, 78, 36, 109, 83, 83, 163, 59, 225, 74, 104, 79, 58, 127,
+ 252, 144, 52, 231, 101, 224, 139, 52, 181, 171, 154, 43, 215,
+ ];
+ let x = [
+ 236, 219, 129, 50, 196, 196, 170, 157, 179, 88, 71, 155, 243, 42, 69, 108, 238,
+ 251, 242, 152, 38, 90, 120, 148, 236, 215, 166, 155, 49, 32, 64, 183,
+ ];
+
+ let expected = [
+ 157, 152, 47, 97, 226, 116, 212, 144, 157, 93, 122, 3, 239, 211, 157, 66, 20, 33,
+ 133, 93, 0, 4, 53, 86, 167, 67, 88, 98, 125, 11, 137, 122, 142, 17, 16, 84, 146,
+ 17, 49, 11, 228, 22, 128, 161, 57, 188, 136, 75, 96, 197, 3, 206, 224, 204, 65,
+ 149, 190, 101, 231, 161, 232, 35, 87, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ let actual = initial_hash(hlen, kib, passes, &p, &s, &k, &x).unwrap();
+ assert_eq!(expected.as_ref(), actual.as_ref());
+ }
+
+ #[test]
+ fn initial_hash_test_2() {
+ let hlen = 1360327050;
+ let kib = 266855870;
+ let passes = 263947785;
+ let p = [
+ 62, 145, 210, 51, 41, 168, 197, 154, 64, 67, 181, 144, 73, 11, 90, 166, 13, 111,
+ 86, 19, 81, 103, 83, 26, 140, 110, 143, 91, 235, 175, 58, 220, 123, 172, 214, 144,
+ 96, 251, 34, 63, 205, 120, 252, 224, 127, 254, 117, 205, 251, 191, 5, 118, 112,
+ 219, 91, 16, 184, 80, 197, 229, 23, 239, 138, 200,
+ ];
+ let s = [
+ 229, 128, 59, 80, 127, 134, 112, 194, 29, 49, 206, 111, 254, 195, 72, 98, 51, 39,
+ 50, 55, 55, 47, 68, 231, 82, 91, 229, 226, 244, 102, 59, 32, 184, 171, 121, 57, 3,
+ 17, 155, 176, 102, 49, 168, 247, 225, 227, 144, 26, 15, 0, 233, 123, 199, 73, 73,
+ 150, 137, 140, 175, 219, 91, 4, 219, 129,
+ ];
+ let k = [
+ 230, 122, 163, 153, 60, 26, 74, 62, 99, 255, 192, 203, 137, 28, 66, 180, 48, 149,
+ 160, 238, 39, 236, 220, 231, 11, 133, 212, 190, 162, 126, 166, 173,
+ ];
+ let x = [
+ 76, 234, 237, 208, 211, 225, 108, 104, 95, 239, 241, 60, 218, 47, 169, 88, 111,
+ 253, 169, 144, 188, 39, 47, 249, 196, 104, 215, 24, 167, 126, 250, 143, 174, 175,
+ 167, 159, 115, 77, 127, 219, 142, 76, 37, 104, 64, 174, 241, 190, 204, 160, 149,
+ 122, 142, 40, 42, 235, 47, 173, 11, 59, 45, 8, 133, 143,
+ ];
+
+ let expected = [
+ 75, 173, 222, 46, 97, 96, 90, 145, 123, 113, 146, 135, 56, 148, 100, 59, 28, 233,
+ 228, 56, 215, 15, 138, 5, 90, 30, 128, 111, 131, 160, 92, 32, 97, 76, 216, 81, 134,
+ 15, 239, 64, 239, 203, 191, 226, 71, 213, 149, 238, 65, 124, 102, 1, 150, 230, 41,
+ 132, 23, 176, 221, 217, 237, 150, 154, 249, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ let actual = initial_hash(hlen, kib, passes, &p, &s, &k, &x).unwrap();
+ assert_eq!(expected.as_ref(), actual.as_ref());
+ }
+
+ #[test]
+ fn initial_hash_test_3() {
+ let hlen = 710460332;
+ let kib = 75212384;
+ let passes = 113373009;
+ let p = [
+ 168, 246, 172, 189, 26, 25, 31, 227, 200, 19, 116, 185, 146, 217, 171, 125, 243,
+ 174, 179, 205, 67, 207, 224, 58, 252, 44, 132, 238, 174, 187, 196, 87, 75, 2, 130,
+ 86, 210, 179, 68, 75, 245, 217, 253, 148, 43, 88, 95, 4, 28, 124, 121, 203, 234,
+ 191, 91, 36, 69, 97, 241, 15, 2, 96, 46, 144, 136, 221, 112, 40, 120, 177, 41, 176,
+ 201, 2, 21, 217, 40, 94, 247, 62, 75, 68, 105, 41, 89, 211, 228, 254, 159, 194,
+ 175, 181, 134, 15, 249, 230, 169, 62, 237, 134, 45, 16, 180, 228, 171, 220, 129,
+ 254, 73, 175, 56, 51, 219, 122, 237, 223, 110, 172, 144, 220, 174, 241, 138, 155,
+ 204, 39, 183, 156,
+ ];
+ let s = [
+ 36, 185, 70, 134, 9, 131, 213, 227, 104, 174, 196, 186, 87, 63, 161, 245, 169, 29,
+ 72, 60, 248, 48, 0, 27, 179, 15, 177, 233, 121, 31, 13, 19, 103, 106, 105, 187,
+ 243, 50, 218, 0, 214, 73, 157, 103, 160, 229, 125, 160, 213, 199, 121, 21, 153, 34,
+ 73, 115, 232, 217, 223, 76, 189, 187, 123, 136, 128, 127, 123, 37, 188, 216, 194,
+ 184, 212, 137, 197, 19, 101, 25, 141, 7, 7, 85, 192, 179, 136, 244, 104, 84, 142,
+ 72, 22, 162, 101, 54, 5, 106, 29, 22, 177, 47, 141, 112, 136, 153, 89, 125, 97, 25,
+ 203, 169, 236, 24, 27, 144, 224, 147, 125, 1, 22, 191, 120, 13, 191, 76, 63, 18,
+ 238, 148,
+ ];
+ let k = [
+ 243, 70, 162, 106, 101, 169, 16, 249, 31, 59, 234, 10, 196, 82, 36, 84, 153, 233,
+ 22, 14, 198, 100, 178, 225, 157, 177, 233, 83, 27, 133, 114, 254,
+ ];
+ let x = [
+ 156, 6, 232, 138, 61, 133, 190, 151, 160, 41, 167, 51, 218, 112, 90, 97, 32, 238,
+ 123, 89, 149, 121, 166, 50, 186, 121, 189, 128, 157, 235, 134, 168, 14, 193, 154,
+ 215, 246, 8, 104, 94, 179, 239, 93, 17, 78, 184, 192, 166, 158, 222, 175, 235, 201,
+ 9, 117, 81, 127, 101, 75, 124, 44, 112, 211, 224, 221, 243, 130, 33, 68, 216, 191,
+ 127, 61, 180, 118, 25, 233, 51, 241, 68, 92, 159, 49, 95, 146, 142, 65, 93, 113,
+ 97, 80, 237, 242, 15, 15, 162, 67, 84, 108, 168, 165, 20, 230, 119, 19, 90, 13, 30,
+ 93, 152, 103, 90, 218, 174, 147, 32, 255, 33, 15, 28, 11, 232, 126, 184, 183, 222,
+ 6, 111,
+ ];
+
+ let expected = [
+ 201, 203, 51, 82, 36, 53, 35, 146, 170, 88, 139, 252, 221, 33, 198, 174, 96, 86,
+ 241, 236, 112, 62, 172, 141, 168, 39, 134, 110, 91, 103, 141, 136, 207, 165, 236,
+ 236, 58, 237, 193, 139, 30, 191, 244, 2, 176, 123, 134, 44, 251, 101, 255, 220,
+ 218, 109, 249, 231, 200, 45, 232, 240, 155, 10, 93, 111, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ let actual = initial_hash(hlen, kib, passes, &p, &s, &k, &x).unwrap();
+ assert_eq!(expected.as_ref(), actual.as_ref());
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_test_same_result(
+ hlen: u32,
+ kib: u32,
+ passes: u32,
+ p: Vec<u8>,
+ s: Vec<u8>,
+ k: Vec<u8>,
+ x: Vec<u8>,
+ ) -> bool {
+ let first = initial_hash(hlen, kib, passes, &p, &s, &k, &x).unwrap();
+ let second = initial_hash(hlen, kib, passes, &p, &s, &k, &x).unwrap();
+
+ first.as_ref() == second.as_ref()
+ }
+ }
+
+ mod test_extended_hash {
+ use super::*;
+
+ #[test]
+ fn err_on_empty_dst() {
+ let mut out = [0u8; 0];
+ let input = [255u8; 256];
+
+ assert!(extended_hash(&input, &mut out).is_err());
+ }
+
+ #[test]
+ fn extended_hash_test_1() {
+ let mut out = [
+ 49, 22, 190, 96, 55, 242, 247, 115, 242, 1, 96, 161, 138, 72, 108, 211, 135, 164,
+ 123, 9, 199, 223, 163, 248, 176, 81, 208, 255, 71, 67, 29, 215,
+ ];
+ let input = [
+ 33, 25, 138, 88, 116, 24, 7, 244, 116, 129, 14, 117, 135, 154, 207, 46, 65, 155,
+ 192, 39, 111, 117, 36, 109, 102, 49, 181, 172, 217, 21, 6, 201, 4, 229, 156, 175,
+ 201, 35, 84, 130, 195, 50, 97, 38, 137, 182, 162, 240, 16, 46, 202, 146, 2, 73,
+ 136, 4, 215, 200, 149, 252, 18, 47, 218, 17,
+ ];
+ let expected = [
+ 23, 122, 170, 179, 137, 61, 145, 86, 70, 228, 124, 82, 24, 135, 208, 96, 33, 127,
+ 145, 136, 189, 60, 123, 34, 55, 118, 245, 41, 197, 229, 209, 3,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn extended_hash_test_2() {
+ let mut out = [
+ 241, 8, 207, 144, 211, 141, 215, 81, 145, 190, 184, 85, 99, 72, 157, 91, 32, 190,
+ 241, 192, 207, 205, 157, 119, 110, 28, 49, 117, 239, 220, 185, 246, 211, 188, 166,
+ 238, 223, 105, 163, 231, 21, 241, 70, 115, 155, 22, 160, 23, 242, 129, 144, 216,
+ 190, 110, 143, 221, 54, 4, 71, 239, 101, 95, 155, 196,
+ ];
+ let input = [
+ 66, 65, 147, 227, 144, 232, 121, 134, 153, 127, 210, 161, 10, 39, 254, 174, 144,
+ 104, 74, 63, 126, 53, 247, 145, 227, 229, 29, 255, 140, 246, 13, 65, 179, 149, 86,
+ 150, 216, 81, 178, 131, 136, 40, 139, 220, 43, 185, 119, 249, 161, 244, 0, 177,
+ 176, 139, 164, 135, 21, 68, 105, 204, 39, 107, 73, 47, 244, 228, 117, 203, 63, 82,
+ 81, 196, 135, 192, 148, 245, 77, 174, 184, 84, 150, 56, 11, 183, 234, 245, 88, 182,
+ 248, 223, 124, 252, 170, 111, 9, 48, 22, 227, 18, 118, 136, 22, 250, 22, 108, 229,
+ 176, 186, 19, 45, 67, 105, 19, 45, 94, 113, 16, 116, 215, 188, 91, 105, 36, 18, 77,
+ 235, 195, 113,
+ ];
+ let expected = [
+ 33, 81, 20, 93, 250, 207, 85, 11, 227, 90, 81, 170, 97, 236, 60, 207, 156, 65, 52,
+ 186, 53, 114, 252, 33, 118, 184, 12, 21, 239, 186, 19, 84, 98, 59, 219, 146, 117,
+ 222, 212, 217, 233, 173, 84, 38, 188, 102, 165, 73, 137, 64, 18, 214, 51, 167, 180,
+ 113, 50, 196, 175, 138, 96, 109, 95, 61,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn extended_hash_test_3() {
+ let mut out = [
+ 70, 156, 46, 182, 87, 221, 0, 156, 124, 47, 167, 94, 57, 77, 222, 142, 130, 234,
+ 218, 139, 119, 27, 170, 129, 232, 219, 152, 79, 7, 237, 81, 3, 203, 33, 116, 167,
+ 159, 232, 31, 143, 142, 217, 118, 158, 40, 42, 42, 131, 249, 99, 63, 136, 182, 122,
+ 161, 8, 77, 7, 243, 7, 152, 54, 211, 102, 158, 7, 238, 103, 203, 249, 40, 204, 13,
+ 246, 0, 169, 235, 154, 14, 86, 4, 183, 145, 233, 248, 125, 155, 22, 8, 207, 80, 40,
+ 159, 55, 207, 151, 248, 170, 101, 233, 3, 68, 253, 88, 77, 164, 182, 211, 154, 101,
+ 210, 199, 58, 98, 110, 127, 189, 180, 158, 38, 30, 97, 124, 55, 82, 39, 183, 115,
+ ];
+ let input = [
+ 103, 132, 147, 55, 198, 201, 33, 151, 217, 248, 118, 190, 164, 159, 224, 197, 172,
+ 89, 93, 146, 170, 143, 72, 88, 75, 13, 41, 237, 20, 77, 117, 54, 100, 76, 198, 85,
+ 222, 182, 69, 119, 55, 251, 165, 141, 16, 105, 157, 25, 14, 70, 182, 131, 95, 21,
+ 156, 64, 3, 133, 179, 66, 9, 33, 181, 158, 165, 212, 142, 86, 22, 236, 235, 17,
+ 243, 34, 13, 109, 56, 111, 63, 75, 217, 153, 60, 159, 172, 233, 145, 142, 181, 136,
+ 210, 174, 187, 55, 153, 214, 105, 233, 196, 69, 64, 0, 59, 25, 21, 27, 233, 87,
+ 119, 31, 184, 15, 160, 55, 228, 132, 41, 110, 255, 79, 90, 141, 183, 156, 251, 89,
+ 90, 151, 199, 149, 220, 31, 85, 85, 87, 253, 79, 97, 18, 125, 251, 227, 120, 236,
+ 196, 203, 135, 195, 194, 160, 129, 89, 40, 111, 160, 222, 101, 149, 109, 153, 90,
+ 156, 220, 219, 89, 128, 8, 17, 104, 108, 145, 233, 121, 100, 124, 151, 96, 39, 187,
+ 132, 173, 9, 74, 154, 199, 126, 104, 241, 198, 190, 148, 221, 29, 50, 234, 19, 75,
+ 139, 135, 34, 247, 247, 226, 245, 142, 140, 152, 53, 210, 65, 174, 168, 70, 41, 13,
+ 11, 108, 29, 2, 93, 24, 156, 209, 159, 123, 80, 76, 111, 245, 39, 81, 252, 114, 82,
+ 175, 107, 42, 34, 131, 221, 209, 23, 231, 174, 242, 10, 17, 77, 251, 138, 239, 213,
+ 157, 197, 87, 96,
+ ];
+ let expected = [
+ 247, 38, 177, 59, 225, 220, 244, 197, 13, 169, 51, 184, 170, 167, 18, 78, 77, 196,
+ 23, 182, 207, 227, 211, 203, 66, 202, 238, 18, 72, 7, 110, 92, 162, 84, 125, 185,
+ 132, 129, 210, 217, 217, 93, 17, 93, 58, 18, 31, 165, 3, 194, 111, 223, 231, 8,
+ 120, 102, 201, 76, 149, 253, 233, 246, 199, 21, 157, 107, 186, 47, 123, 209, 94,
+ 151, 56, 53, 33, 8, 116, 26, 58, 53, 255, 51, 184, 18, 241, 179, 54, 15, 181, 18,
+ 117, 48, 83, 190, 250, 39, 126, 145, 178, 150, 185, 87, 172, 5, 176, 110, 227, 142,
+ 233, 63, 85, 225, 162, 85, 179, 166, 250, 222, 5, 10, 139, 187, 172, 105, 171, 171,
+ 140, 253,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn extended_hash_test_4() {
+ let mut out = [
+ 231, 57, 92, 140, 212, 20, 239, 34, 56, 165, 207, 203, 237, 63, 103, 245, 135, 137,
+ 173, 240, 171, 105, 161, 221, 2, 15, 36, 47, 166, 126, 151, 21, 223, 34, 8, 141,
+ 193, 50, 70, 138, 65, 197, 165, 167, 25, 207, 114, 124, 147, 80, 192, 179, 171, 18,
+ 58, 180, 3, 79, 233, 231, 156, 157, 106, 2,
+ ];
+ let input = [
+ 213, 96, 143, 63, 224, 241, 183, 146, 44, 45, 66, 96, 200, 213, 151, 108, 41, 142,
+ 193, 159, 45, 198, 28, 146, 65, 13, 39, 36, 153, 46, 225, 14,
+ ];
+ let expected = [
+ 174, 131, 211, 180, 105, 12, 67, 55, 16, 72, 125, 125, 211, 93, 64, 180, 179, 188,
+ 77, 113, 119, 181, 98, 54, 13, 146, 57, 92, 43, 232, 224, 183, 219, 138, 143, 234,
+ 232, 151, 33, 76, 158, 96, 170, 104, 200, 127, 55, 239, 145, 241, 224, 146, 0, 11,
+ 64, 16, 212, 151, 227, 7, 65, 234, 92, 45,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn extended_hash_test_5() {
+ let mut out = [
+ 53, 56, 9, 207, 79, 196, 6, 94, 170, 197, 204, 233, 69, 124, 20, 228, 227, 59, 102,
+ 30, 88, 45, 245, 144, 69, 50, 72, 163, 31, 100, 44, 12, 203, 9, 253, 13, 253, 221,
+ 216, 186, 92, 164, 37, 55, 195, 31, 13, 39, 110, 180, 40, 167, 40, 236, 138, 203,
+ 123, 174, 121, 219, 133, 211, 184, 133, 255, 239, 233, 193, 203, 90, 48, 59, 95,
+ 111, 55, 11, 95, 147, 178, 164, 241, 231, 109, 21, 16, 161, 192, 86, 156, 138, 137,
+ 224, 139, 52, 142, 192, 189, 231, 170, 54, 55, 150, 12, 122, 51, 250, 167, 127, 5,
+ 204, 63, 34, 71, 221, 162, 35, 33, 246, 22, 187, 187, 2, 41, 223, 81, 143, 231, 77,
+ ];
+ let input = [
+ 92, 110, 199, 162, 60, 226, 227, 26, 123, 30, 136, 146, 116, 38, 44, 194, 254, 14,
+ 137, 67, 183, 2, 112, 194, 30, 15, 100, 215, 248, 47, 223, 93, 156, 71, 98, 247,
+ 54, 74, 92, 233, 219, 165, 1, 45, 162, 225, 7, 80, 237, 172, 245, 25, 80, 162, 216,
+ 83, 35, 122, 156, 143, 55, 19, 5, 26,
+ ];
+ let expected = [
+ 253, 153, 55, 223, 21, 172, 36, 50, 109, 171, 45, 24, 40, 215, 239, 116, 92, 149,
+ 31, 40, 17, 99, 42, 25, 114, 52, 167, 230, 63, 36, 226, 178, 222, 163, 247, 175,
+ 100, 118, 54, 51, 223, 11, 164, 68, 126, 157, 94, 255, 196, 53, 177, 231, 81, 55,
+ 1, 250, 85, 91, 89, 45, 15, 121, 66, 157, 195, 162, 97, 243, 33, 195, 149, 253,
+ 193, 24, 150, 106, 234, 158, 122, 28, 52, 72, 48, 109, 206, 190, 116, 50, 163, 191,
+ 208, 86, 231, 170, 11, 210, 251, 135, 50, 46, 160, 202, 72, 101, 45, 24, 202, 72,
+ 210, 25, 239, 0, 229, 47, 200, 219, 202, 0, 39, 195, 197, 148, 15, 32, 211, 167,
+ 196, 128,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[test]
+ fn extended_hash_test_6() {
+ let mut out = [
+ 253, 1, 93, 186, 15, 159, 80, 7, 174, 85, 112, 241, 193, 170, 254, 103, 204, 254,
+ 154, 58, 228, 243, 244, 192, 223, 174, 103, 229, 21, 66, 203, 203, 221, 186, 76,
+ 40, 49, 66, 170, 52, 140, 254, 142, 95, 23, 200, 19, 117, 252, 9, 144, 94, 63, 14,
+ 66, 162, 168, 125, 112, 76, 45, 166, 241, 179, 54, 75, 107, 140, 92, 95, 211, 138,
+ 209, 143, 237, 130, 180, 19, 156, 242, 65, 22, 55, 228, 23, 106, 119, 14, 140, 66,
+ 188, 206, 107, 93, 130, 123, 6, 10, 85, 250, 177, 195, 46, 248, 177, 195, 86, 150,
+ 21, 10, 160, 108, 113, 75, 253, 51, 12, 173, 254, 71, 236, 160, 176, 130, 71, 161,
+ 205, 146, 104, 63, 189, 90, 117, 110, 141, 16, 18, 246, 158, 71, 201, 242, 53, 169,
+ 5, 3, 91, 227, 157, 11, 127, 150, 180, 200, 73, 27, 2, 78, 209, 89, 93, 78, 2, 136,
+ 70, 46, 65, 181, 217, 158, 54, 143, 135, 229, 217, 239, 22, 175, 156, 176, 111, 54,
+ 141, 230, 133, 232, 137, 100, 81, 147, 71, 176, 113, 125, 88, 48, 170, 19, 156,
+ 184, 91, 166, 195, 251, 143, 253, 135, 107, 215, 209, 224, 40, 96, 56, 222, 118,
+ 247, 22, 0, 251, 215, 62, 179, 190, 112, 75, 79, 96, 148, 246, 46, 15, 91, 117,
+ 142, 221, 133, 155, 237, 126, 144, 104, 240, 124, 130, 222, 19, 93, 87, 120, 83,
+ 117, 77, 75, 105, 104,
+ ];
+ let input = [
+ 89, 106, 243, 203, 190, 196, 239, 41, 217, 53, 96, 178, 255, 156, 212, 103, 117,
+ 255, 25, 219, 215, 212, 74, 47, 227, 67, 151, 151, 241, 100, 32, 178, 197, 211, 63,
+ 206, 247, 215, 141, 236, 41, 248, 232, 241, 106, 178, 52, 133, 83, 177, 65, 177,
+ 253, 118, 157, 226, 225, 137, 134, 127, 231, 48, 46, 156, 51, 224, 102, 94, 205,
+ 30, 222, 59, 173, 243, 205, 117, 78, 112, 160, 35, 66, 220, 113, 146, 100, 194, 56,
+ 85, 28, 75, 57, 59, 243, 201, 250, 140, 147, 24, 253, 84, 135, 91, 221, 190, 128,
+ 225, 118, 27, 74, 251, 27, 182, 254, 122, 44, 48, 222, 131, 32, 176, 254, 250, 200,
+ 2, 38, 202, 255, 207,
+ ];
+ let expected = [
+ 22, 21, 67, 184, 94, 20, 98, 6, 113, 81, 65, 110, 70, 42, 13, 58, 26, 213, 184,
+ 242, 234, 133, 185, 122, 112, 235, 18, 11, 94, 199, 64, 107, 116, 55, 49, 85, 178,
+ 118, 146, 51, 230, 150, 214, 229, 90, 162, 178, 225, 106, 138, 169, 206, 77, 161,
+ 112, 162, 86, 101, 48, 90, 227, 247, 147, 186, 120, 84, 101, 196, 141, 213, 215,
+ 115, 201, 150, 35, 182, 156, 243, 87, 242, 165, 45, 128, 127, 70, 51, 225, 40, 27,
+ 250, 173, 46, 109, 116, 254, 202, 206, 112, 48, 205, 21, 164, 129, 192, 181, 119,
+ 195, 126, 38, 177, 107, 55, 149, 126, 227, 44, 254, 225, 104, 15, 236, 141, 233,
+ 110, 132, 133, 241, 17, 210, 26, 22, 175, 135, 199, 106, 200, 214, 45, 20, 83, 164,
+ 49, 202, 69, 203, 191, 21, 92, 101, 206, 109, 136, 144, 123, 108, 24, 121, 142, 77,
+ 91, 122, 248, 117, 85, 82, 181, 228, 192, 197, 111, 169, 161, 30, 12, 201, 127, 24,
+ 17, 185, 88, 4, 126, 83, 107, 76, 6, 6, 146, 205, 164, 202, 151, 11, 189, 205, 159,
+ 146, 245, 79, 13, 127, 23, 148, 219, 156, 104, 161, 201, 155, 81, 126, 57, 34, 201,
+ 118, 110, 163, 135, 194, 38, 9, 2, 205, 54, 192, 55, 214, 98, 23, 35, 70, 113, 120,
+ 68, 206, 127, 130, 174, 252, 254, 135, 37, 160, 144, 108, 29, 86, 108, 159, 148,
+ 221, 54, 153, 234, 194, 103,
+ ];
+ extended_hash(&input, &mut out).unwrap();
+ assert_eq!(expected.as_ref(), out.as_ref());
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_test_same_result(input: Vec<u8>, out: Vec<u8>) -> bool {
+ let mut first = out.clone();
+ let mut second = out.clone();
+
+ if out.is_empty() && extended_hash(&input, &mut first).is_err() {
+ return true;
+ }
+
+ extended_hash(&input, &mut first).unwrap();
+ extended_hash(&input, &mut second).unwrap();
+
+ first == second
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_test_diff_result(input: Vec<u8>, out: Vec<u8>) -> bool {
+ let mut first = out.clone();
+ let mut second = out.clone();
+
+ if out.is_empty() && extended_hash(&input, &mut first).is_err() {
+ return true;
+ }
+
+ extended_hash(&input, &mut first).unwrap();
+ extended_hash(&first, &mut second).unwrap();
+
+ first != second
+ }
+ }
+
+ mod test_gidx {
+ use super::*;
+
+ #[test]
+ fn gidx_test() {
+ let n_blocks = 4096;
+ let segment_length = 1024;
+ let passes = 3;
+
+ let mut gidx = Gidx::new(n_blocks, passes, segment_length);
+ let mut tmp_block = [0u64; 128];
+
+ let offset = 2;
+ let pass_n = 0;
+ let segment_n = 0;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1022] = [
+ 0, 1, 0, 3, 2, 1, 6, 3, 7, 8, 10, 11, 11, 4, 14, 7, 16, 13, 6, 17, 5, 20, 11, 19,
+ 20, 2, 26, 26, 22, 21, 28, 19, 31, 18, 30, 35, 31, 33, 35, 31, 28, 35, 24, 43, 41,
+ 42, 44, 41, 36, 32, 38, 48, 43, 53, 51, 42, 4, 44, 17, 45, 53, 49, 38, 27, 7, 24,
+ 53, 59, 24, 45, 19, 38, 55, 49, 74, 60, 41, 44, 17, 60, 0, 78, 45, 32, 83, 10, 18,
+ 65, 60, 65, 84, 26, 1, 93, 48, 67, 68, 97, 30, 76, 68, 53, 75, 42, 83, 25, 106, 2,
+ 108, 101, 110, 61, 34, 94, 14, 92, 26, 69, 108, 51, 94, 69, 122, 123, 120, 94, 3,
+ 67, 125, 39, 97, 14, 37, 41, 112, 124, 18, 125, 96, 107, 134, 134, 69, 121, 139,
+ 112, 52, 98, 138, 71, 129, 134, 126, 152, 153, 150, 43, 109, 152, 159, 157, 61,
+ 146, 153, 47, 42, 166, 78, 30, 43, 132, 171, 121, 149, 119, 172, 115, 13, 132, 140,
+ 165, 45, 29, 142, 76, 78, 175, 187, 150, 120, 182, 153, 192, 188, 67, 191, 193,
+ 125, 127, 183, 57, 138, 186, 24, 89, 40, 56, 207, 196, 64, 62, 211, 195, 70, 184,
+ 87, 45, 198, 53, 181, 129, 62, 164, 142, 59, 223, 173, 142, 228, 82, 230, 136, 160,
+ 194, 203, 235, 155, 181, 216, 143, 139, 102, 210, 180, 198, 235, 93, 177, 149, 245,
+ 245, 177, 252, 253, 20, 198, 143, 216, 102, 181, 91, 259, 200, 263, 106, 240, 200,
+ 267, 229, 160, 57, 116, 71, 203, 274, 182, 13, 237, 241, 202, 85, 278, 269, 261,
+ 219, 56, 283, 186, 280, 215, 265, 195, 292, 137, 293, 294, 277, 224, 106, 285, 300,
+ 82, 302, 289, 234, 236, 300, 242, 277, 52, 214, 244, 304, 259, 179, 235, 316, 305,
+ 28, 230, 242, 313, 59, 159, 133, 86, 103, 171, 225, 300, 223, 291, 233, 325, 144,
+ 41, 164, 261, 206, 70, 213, 44, 339, 229, 154, 279, 338, 218, 348, 326, 288, 344,
+ 284, 329, 257, 345, 353, 199, 276, 359, 279, 349, 8, 363, 357, 3, 364, 360, 262,
+ 82, 322, 366, 183, 197, 244, 375, 165, 377, 79, 106, 222, 321, 299, 61, 264, 340,
+ 283, 66, 382, 47, 321, 162, 374, 385, 26, 242, 392, 276, 384, 296, 306, 77, 23,
+ 105, 381, 316, 248, 40, 405, 112, 410, 409, 141, 261, 149, 275, 267, 39, 80, 394,
+ 259, 310, 421, 68, 70, 283, 361, 398, 90, 308, 83, 220, 87, 228, 342, 70, 337, 437,
+ 284, 179, 440, 440, 308, 149, 421, 42, 86, 419, 33, 23, 390, 132, 389, 364, 433,
+ 52, 222, 342, 291, 423, 459, 191, 382, 118, 463, 164, 384, 358, 150, 455, 246, 432,
+ 456, 473, 161, 309, 117, 109, 341, 283, 441, 40, 470, 254, 484, 36, 482, 430, 488,
+ 101, 484, 344, 491, 425, 474, 357, 403, 481, 195, 454, 360, 501, 470, 170, 495,
+ 277, 377, 441, 399, 362, 19, 436, 482, 392, 514, 305, 495, 508, 170, 102, 276, 315,
+ 89, 380, 433, 460, 523, 527, 50, 422, 191, 162, 532, 525, 459, 368, 71, 492, 208,
+ 173, 38, 443, 417, 57, 460, 521, 199, 356, 428, 180, 550, 497, 487, 546, 148, 461,
+ 389, 535, 360, 420, 460, 552, 449, 290, 558, 360, 154, 424, 240, 45, 428, 392, 566,
+ 555, 559, 109, 5, 404, 576, 118, 206, 543, 349, 173, 513, 287, 586, 380, 311, 87,
+ 206, 358, 182, 526, 447, 404, 437, 271, 417, 3, 237, 439, 534, 602, 231, 595, 522,
+ 366, 544, 491, 520, 278, 604, 607, 595, 370, 604, 509, 602, 463, 163, 270, 615,
+ 123, 563, 566, 626, 611, 579, 629, 58, 436, 522, 338, 527, 451, 41, 549, 635, 431,
+ 640, 387, 613, 571, 12, 510, 527, 593, 648, 465, 484, 625, 325, 197, 651, 617, 429,
+ 218, 627, 490, 656, 640, 79, 203, 480, 655, 627, 648, 648, 665, 132, 291, 667, 620,
+ 296, 243, 574, 673, 609, 642, 680, 484, 669, 239, 461, 678, 422, 677, 227, 430,
+ 503, 468, 78, 503, 112, 563, 639, 477, 232, 649, 345, 679, 473, 448, 459, 577, 18,
+ 315, 692, 618, 534, 656, 709, 294, 400, 648, 242, 488, 706, 198, 404, 369, 304,
+ 699, 698, 394, 572, 493, 216, 725, 406, 723, 548, 580, 158, 450, 731, 735, 25, 694,
+ 426, 741, 256, 98, 407, 12, 558, 445, 566, 748, 596, 180, 663, 663, 170, 330, 636,
+ 686, 738, 656, 679, 89, 605, 484, 155, 599, 619, 629, 55, 683, 474, 316, 311, 474,
+ 50, 21, 599, 202, 711, 477, 719, 77, 782, 737, 688, 427, 712, 165, 212, 437, 716,
+ 718, 792, 486, 606, 751, 61, 708, 667, 677, 116, 17, 787, 591, 678, 494, 4, 675,
+ 148, 796, 747, 524, 434, 603, 674, 744, 715, 629, 72, 1, 748, 735, 542, 808, 688,
+ 197, 826, 387, 757, 810, 41, 366, 826, 688, 814, 483, 319, 210, 37, 803, 51, 671,
+ 396, 690, 268, 292, 823, 599, 258, 595, 748, 844, 610, 454, 689, 62, 796, 687, 853,
+ 465, 257, 404, 811, 367, 665, 724, 520, 319, 667, 353, 843, 761, 870, 694, 606,
+ 597, 98, 867, 275, 878, 407, 389, 811, 272, 745, 416, 46, 401, 875, 316, 808, 687,
+ 683, 589, 392, 589, 245, 759, 637, 889, 472, 746, 363, 337, 884, 726, 481, 827,
+ 764, 447, 409, 911, 69, 872, 660, 567, 752, 825, 320, 495, 447, 807, 454, 838, 870,
+ 66, 737, 805, 906, 350, 334, 849, 713, 277, 698, 930, 795, 930, 840, 670, 933, 707,
+ 873, 35, 731, 149, 667, 671, 208, 833, 110, 814, 113, 880, 506, 951, 255, 48, 956,
+ 816, 951, 138, 274, 528, 154, 592, 778, 906, 572, 621, 955, 751, 802, 964, 801,
+ 891, 410, 513, 969, 896, 971, 286, 647, 76, 582, 767, 983, 822, 262, 288, 79, 895,
+ 973, 891, 982, 965, 813, 721, 905, 771, 981, 954, 311, 68, 912, 671, 643, 1006, 16,
+ 259, 49, 1009, 1012, 828, 416, 1015, 878, 802, 213, 230, 567, 392,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 0;
+ let segment_n = 1;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 63, 227, 849, 503, 967, 726, 979, 1023, 1025, 514, 762, 161, 674, 961, 1033, 1035,
+ 440, 387, 3, 622, 1041, 1030, 17, 773, 934, 469, 197, 1004, 1048, 908, 357, 827,
+ 537, 950, 1000, 1049, 334, 219, 1006, 758, 1059, 137, 722, 462, 401, 236, 216,
+ 1045, 227, 1010, 1072, 1062, 755, 771, 922, 648, 26, 59, 1048, 1078, 626, 1034,
+ 157, 167, 552, 835, 1087, 936, 1028, 339, 442, 303, 207, 1033, 411, 348, 672, 954,
+ 888, 491, 815, 937, 733, 1079, 275, 427, 1103, 148, 571, 1078, 1069, 1113, 492,
+ 889, 962, 733, 1117, 921, 474, 277, 934, 555, 1035, 172, 1053, 804, 1079, 708, 206,
+ 1044, 1125, 454, 1086, 686, 408, 1136, 335, 1001, 200, 671, 341, 1115, 1016, 1043,
+ 1088, 629, 782, 600, 793, 684, 1056, 671, 1040, 4, 1156, 1037, 1145, 694, 607, 804,
+ 1125, 127, 829, 858, 580, 782, 661, 377, 1098, 946, 913, 90, 1070, 1099, 1064, 790,
+ 846, 675, 1042, 724, 738, 682, 1033, 994, 997, 1111, 378, 934, 771, 629, 1120,
+ 1193, 1177, 33, 1183, 691, 346, 1016, 374, 475, 110, 1185, 966, 730, 1118, 1004,
+ 237, 347, 803, 50, 790, 1136, 797, 146, 1214, 1162, 655, 1192, 1180, 1219, 1171,
+ 428, 252, 552, 1221, 1164, 1223, 834, 369, 696, 1197, 1187, 483, 1179, 1236, 982,
+ 890, 1182, 1238, 745, 1215, 756, 1188, 1244, 1151, 712, 718, 1205, 1167, 799, 1211,
+ 1253, 86, 1163, 1155, 1095, 151, 255, 1160, 765, 1080, 555, 963, 150, 1197, 1189,
+ 945, 1154, 1268, 840, 392, 172, 1191, 1108, 1271, 1059, 768, 813, 719, 964, 824,
+ 577, 1205, 1077, 307, 1199, 1287, 1066, 244, 1177, 38, 1004, 1281, 1273, 518, 1077,
+ 1263, 1225, 1043, 1243, 1199, 1237, 17, 368, 1021, 1245, 971, 1303, 849, 808, 1312,
+ 1313, 1161, 1185, 1154, 1215, 1201, 1037, 1269, 324, 649, 1092, 812, 983, 1305,
+ 782, 1050, 1270, 1108, 1327, 1311, 503, 1135, 1045, 1326, 748, 458, 139, 685, 1146,
+ 1338, 1326, 334, 224, 1345, 809, 847, 678, 569, 1316, 1335, 1353, 1114, 353, 1241,
+ 1123, 524, 950, 298, 1058, 631, 1260, 1161, 1315, 1037, 473, 1291, 946, 911, 1187,
+ 33, 1372, 643, 962, 120, 1172, 341, 566, 986, 6, 888, 1118, 1322, 1054, 22, 865,
+ 352, 1208, 1336, 1124, 1143, 1065, 1392, 1183, 1307, 1375, 617, 1351, 139, 1383,
+ 1018, 1392, 1402, 1145, 471, 962, 562, 1409, 1374, 1210, 1297, 361, 1085, 1415,
+ 1347, 794, 87, 1073, 759, 1241, 519, 1154, 1259, 1293, 1383, 551, 409, 1429, 587,
+ 64, 1285, 1314, 1305, 1371, 1161, 1196, 572, 1136, 1430, 1141, 926, 1439, 1005,
+ 1088, 354, 574, 1044, 1002, 1285, 707, 1264, 1114, 695, 1449, 1273, 693, 362, 846,
+ 397, 401, 1462, 1089, 1352, 1344, 979, 152, 1303, 985, 398, 1106, 1320, 916, 680,
+ 1475, 1353, 1314, 578, 479, 1045, 1350, 930, 34, 1484, 1028, 131, 64, 1255, 808,
+ 1437, 1168, 1051, 658, 732, 1035, 1346, 199, 640, 1323, 300, 433, 730, 1503, 560,
+ 422, 1371, 729, 1450, 1163, 267, 1496, 1078, 467, 76, 1473, 1498, 1115, 65, 979,
+ 114, 551, 1482, 1166, 1509, 1469, 1526, 1440, 961, 1002, 1530, 1050, 1295, 1161,
+ 1299, 1332, 1038, 1263, 420, 1490, 1495, 578, 1308, 1057, 1105, 620, 965, 1281,
+ 789, 1100, 820, 98, 1508, 942, 176, 939, 515, 51, 997, 849, 1294, 663, 325, 405,
+ 1417, 1544, 1308, 1325, 1492, 790, 975, 1101, 1339, 1470, 1570, 1486, 1567, 1397,
+ 2, 809, 499, 1580, 1578, 1461, 867, 830, 713, 968, 1574, 1587, 136, 1410, 1, 1288,
+ 1186, 1222, 1029, 1326, 1590, 4, 4, 1560, 280, 385, 1462, 54, 1406, 1156, 1035,
+ 1608, 1126, 145, 157, 708, 241, 889, 1426, 1514, 1569, 1607, 1064, 1259, 73, 1560,
+ 412, 802, 623, 1578, 1624, 1617, 1265, 1002, 1383, 1479, 1235, 1499, 1326, 1556,
+ 616, 1567, 1611, 1627, 1611, 141, 394, 384, 1473, 1639, 1113, 549, 1544, 226, 337,
+ 567, 628, 1332, 1612, 1634, 1654, 8, 1016, 1172, 508, 1521, 1308, 245, 545, 1593,
+ 1650, 927, 1668, 1402, 421, 1438, 1024, 444, 1061, 1579, 1496, 1272, 887, 1314,
+ 1187, 276, 574, 472, 1457, 529, 1669, 282, 691, 1553, 1688, 1471, 1694, 1690, 1594,
+ 1675, 1690, 1047, 1632, 1438, 1697, 1649, 59, 1677, 1443, 1420, 1471, 1675, 418,
+ 259, 1085, 788, 339, 64, 987, 5, 1421, 1636, 361, 1312, 1564, 1359, 74, 1666, 653,
+ 1714, 1584, 1192, 341, 1471, 907, 1591, 582, 775, 1412, 1674, 505, 385, 1301, 1505,
+ 1299, 985, 31, 1713, 762, 1747, 1705, 1685, 917, 636, 105, 1528, 513, 881, 1414,
+ 1645, 1602, 1313, 1537, 1746, 1738, 1453, 1625, 1750, 552, 411, 227, 1228, 1615,
+ 288, 1542, 1709, 1277, 1649, 1776, 1327, 1743, 1769, 863, 242, 1005, 1748, 972,
+ 1332, 46, 1758, 1740, 1582, 1789, 361, 678, 250, 576, 587, 1313, 703, 663, 443,
+ 1754, 1422, 1561, 1800, 1034, 452, 1493, 753, 1701, 1408, 145, 60, 692, 1804, 1716,
+ 1749, 1778, 1516, 1176, 1736, 1224, 1750, 368, 429, 1818, 1564, 1789, 711, 1451,
+ 1590, 1641, 1574, 1313, 1833, 1363, 1115, 1812, 1828, 1530, 1444, 928, 1695, 1492,
+ 1566, 289, 1705, 1745, 591, 1664, 517, 1072, 1474, 1327, 1853, 1049, 278, 1828,
+ 1857, 1828, 1543, 482, 1861, 1368, 1610, 1493, 1827, 1610, 975, 1678, 873, 1868,
+ 1765, 1420, 974, 1037, 1244, 1816, 1873, 1625, 108, 1217, 1208, 1360, 63, 1644,
+ 1368, 1860, 1624, 1748, 1661, 1677, 1871, 1594, 1859, 1790, 341, 1896, 1866, 285,
+ 905, 1576, 1575, 232, 1828, 428, 1806, 1531, 872, 1610, 1045, 1910, 769, 1897,
+ 1186, 1854, 1887, 1857, 1861, 980, 1594, 1635, 1892, 722, 1515, 1842, 1139, 1026,
+ 1383, 1920, 1558, 1108, 1831, 1867, 1206, 1390, 1848, 1358, 861, 209, 1909, 1883,
+ 445, 974, 477, 1937, 1391, 1187, 1726, 1253, 47, 1027, 1886, 1760, 1157, 1546, 545,
+ 877, 1192, 1843, 748, 1561, 1481, 318, 1207, 1905, 733, 1879, 784, 768, 1881, 1450,
+ 348, 1881, 949, 1511, 1670, 1966, 492, 1748, 1061, 1612, 1399, 348, 1575, 1736,
+ 639, 1986, 1978, 90, 1318, 1559, 1960, 1073, 1886, 733, 284, 268, 1972, 1969, 1912,
+ 1992, 60, 1457, 1769, 1335, 1345, 1999, 1843, 1925, 1475, 1850, 2004, 1077, 970,
+ 553, 1921, 1676, 1443, 1995, 1975, 660, 1142, 2008, 1453, 933, 1983, 1195, 1906,
+ 645, 627, 1525, 1752, 1490, 1040, 1873, 632, 383, 1590, 1924, 165, 1961, 1543,
+ 1719, 1171, 1881, 2031,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 0;
+ let segment_n = 2;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 1171, 1043, 2046, 209, 1914, 1872, 570, 1427, 931, 1485, 2024, 1760, 2049, 1955,
+ 1265, 1039, 1693, 578, 1665, 1457, 1513, 1283, 2023, 1956, 1744, 1659, 2032, 145,
+ 1887, 1633, 2040, 1456, 440, 2044, 2080, 1856, 947, 976, 2084, 2085, 1826, 1774,
+ 2015, 1858, 701, 830, 2065, 1609, 1680, 1502, 653, 554, 201, 1819, 2081, 1898, 561,
+ 287, 1942, 969, 1981, 1300, 177, 2021, 1968, 772, 475, 1996, 1533, 1846, 1933,
+ 2113, 2115, 2026, 2023, 838, 1863, 857, 1470, 2030, 1990, 1339, 1055, 2021, 511,
+ 1197, 1776, 1718, 209, 1759, 2054, 1010, 210, 2063, 1005, 1586, 2141, 2007, 1323,
+ 347, 19, 68, 1796, 1041, 2053, 912, 2144, 443, 1388, 2154, 2028, 2039, 1528, 2120,
+ 1314, 1868, 2159, 1655, 865, 1852, 939, 129, 2168, 797, 707, 338, 1918, 1965, 1541,
+ 1983, 1942, 1160, 2049, 2126, 1974, 2075, 1326, 1557, 1700, 1377, 1054, 1570, 1743,
+ 272, 1884, 1716, 2023, 549, 1984, 1510, 634, 2182, 901, 1773, 1428, 2187, 1703,
+ 1906, 2148, 1394, 790, 584, 331, 2174, 1573, 1347, 1555, 1867, 156, 2206, 912,
+ 1728, 1803, 1883, 1111, 2136, 2221, 2173, 216, 2206, 2215, 1979, 2217, 1439, 1403,
+ 1019, 2150, 1978, 1823, 1838, 1244, 1679, 1882, 1848, 1752, 2241, 53, 2097, 2212,
+ 736, 2230, 2111, 852, 1435, 1829, 2122, 59, 233, 221, 1739, 2212, 1647, 1663, 2204,
+ 1739, 1911, 143, 456, 2044, 1735, 1345, 2027, 2186, 69, 540, 971, 2022, 2050, 1291,
+ 1159, 71, 1582, 2096, 1370, 2171, 1631, 2260, 2210, 1905, 2057, 1708, 2195, 1333,
+ 2141, 1605, 2286, 2211, 2261, 1737, 1239, 2166, 1901, 1709, 2205, 2147, 1918, 2292,
+ 1851, 1339, 2154, 2144, 1027, 197, 1856, 1543, 919, 2076, 1613, 2012, 1100, 1862,
+ 2316, 1717, 1044, 1999, 2298, 2268, 2228, 1454, 1540, 2046, 1667, 1703, 945, 111,
+ 1982, 2324, 2271, 276, 1327, 602, 1538, 1946, 1976, 2244, 2136, 495, 2205, 2333,
+ 1846, 27, 2332, 1047, 2039, 2116, 1116, 1933, 593, 189, 2094, 74, 1020, 1362, 1069,
+ 2203, 1627, 2279, 2332, 468, 2177, 2364, 2086, 1078, 1594, 1539, 2285, 64, 511,
+ 1509, 2155, 323, 2202, 2235, 2350, 1590, 1624, 2320, 2243, 1261, 1460, 2128, 1523,
+ 494, 2186, 874, 749, 1586, 694, 2319, 1978, 1365, 2239, 1042, 2098, 70, 1940, 2343,
+ 2249, 2152, 2259, 1306, 436, 2294, 1027, 2235, 2391, 653, 1056, 2233, 1700, 1388,
+ 2346, 2391, 1215, 2395, 815, 650, 2118, 1831, 2392, 1157, 1297, 2192, 2337, 2265,
+ 2271, 1647, 960, 448, 1558, 1546, 289, 2130, 1831, 2283, 636, 2214, 2409, 2435,
+ 2242, 2209, 584, 1263, 1451, 1024, 1798, 2451, 1482, 124, 1506, 2455, 1119, 1933,
+ 2432, 1953, 2369, 2176, 1838, 77, 788, 1787, 1848, 1711, 2178, 156, 1449, 1395,
+ 2166, 2156, 2161, 1706, 1007, 1225, 2456, 2463, 2412, 1660, 2428, 1643, 1518, 2034,
+ 2421, 651, 1381, 2388, 1425, 2062, 849, 1994, 2495, 2013, 2100, 704, 830, 2499,
+ 2057, 1953, 2419, 214, 1358, 2135, 2498, 2362, 2450, 1182, 1733, 299, 2392, 2514,
+ 2213, 1901, 1301, 791, 1521, 586, 2521, 956, 2353, 1060, 811, 2163, 1398, 1111,
+ 1584, 2434, 1788, 350, 814, 659, 1248, 2244, 517, 2513, 2003, 2270, 1878, 463,
+ 2540, 2489, 2541, 776, 607, 1098, 2374, 2197, 2551, 1493, 1182, 364, 857, 2005,
+ 1803, 2099, 465, 2347, 681, 2254, 1172, 1411, 2443, 2562, 437, 2259, 1535, 2570,
+ 2203, 2557, 2568, 2560, 2152, 2324, 1339, 2396, 121, 1663, 1236, 1577, 2199, 2249,
+ 2581, 2092, 2573, 2586, 224, 2216, 1958, 779, 2586, 1972, 335, 2461, 2284, 1296,
+ 2162, 2579, 46, 2529, 1022, 2412, 1917, 1682, 1431, 59, 2592, 2468, 2472, 2384,
+ 812, 866, 250, 1290, 122, 2064, 1246, 2213, 2618, 1867, 1219, 2250, 1215, 1876,
+ 2368, 2503, 2349, 2251, 186, 2615, 1698, 2591, 2118, 391, 2610, 1786, 2272, 709,
+ 1776, 1466, 2488, 2480, 2462, 2375, 1893, 2637, 2606, 2215, 1787, 1472, 2626, 955,
+ 1964, 2144, 2213, 2645, 2515, 2642, 520, 2354, 967, 2360, 171, 2660, 1611, 2476,
+ 1221, 2290, 2662, 2654, 1093, 2016, 2535, 612, 2032, 1955, 1923, 2676, 1506, 443,
+ 2659, 970, 1344, 2677, 2680, 1686, 54, 2433, 2472, 2187, 2485, 1061, 2216, 2572,
+ 2437, 1379, 2185, 1732, 2111, 2498, 1279, 1467, 2611, 2068, 2138, 2024, 2243, 2241,
+ 2482, 907, 339, 693, 1879, 976, 2415, 2120, 530, 2412, 2693, 278, 783, 111, 486,
+ 1475, 2588, 2728, 2463, 1761, 2379, 2701, 2465, 2504, 2733, 1464, 797, 2114, 1956,
+ 2182, 1404, 1698, 2572, 1246, 2055, 1296, 729, 2143, 1161, 1502, 2140, 2079, 1862,
+ 1546, 2565, 2461, 2631, 1369, 2020, 2755, 2159, 2650, 1459, 2064, 1198, 2680, 2317,
+ 1491, 62, 2369, 547, 539, 2576, 1553, 2633, 1269, 1720, 2768, 1754, 2246, 2393,
+ 1421, 2775, 621, 5, 1070, 2749, 2484, 1639, 2097, 1077, 318, 2757, 2283, 242, 743,
+ 2558, 30, 2711, 1584, 462, 2800, 2802, 2756, 1353, 717, 2745, 733, 1277, 2691,
+ 1112, 1250, 1900, 1796, 2689, 2815, 2209, 526, 2778, 2224, 2808, 1510, 2799, 2743,
+ 1493, 1017, 464, 2504, 2799, 2205, 2670, 1549, 2497, 2568, 228, 2735, 784, 2591,
+ 2027, 2799, 2389, 956, 2725, 2815, 1983, 2647, 2671, 363, 2849, 2848, 578, 1952,
+ 1326, 2158, 2855, 1638, 817, 2846, 1035, 2406, 984, 2299, 1777, 2084, 958, 2386,
+ 2866, 975, 2866, 670, 939, 2865, 1445, 2811, 2501, 2865, 2734, 2393, 204, 2835,
+ 1991, 2868, 1001, 2881, 2495, 1318, 581, 292, 2879, 231, 2664, 1878, 2647, 2303,
+ 2753, 1605, 538, 2345, 2755, 2860, 2663, 2735, 189, 2570, 2087, 162, 72, 2446,
+ 1728, 1153, 2198, 1049, 2875, 745, 1313, 1114, 2692, 592, 820, 469, 872, 1207,
+ 2756, 150, 1494, 1912, 1753, 2567, 2477, 572, 2734, 817, 519, 2471, 962, 1247, 802,
+ 2931, 1552, 2845, 2801, 2891, 2550, 447, 2704, 879, 2909, 1159, 2739, 1542, 2190,
+ 1888, 2530, 2521, 2904, 1095, 2856, 434, 368, 285, 2810, 1488, 2962, 761, 1732,
+ 2410, 2934, 2856, 2376, 1431, 2683, 2902, 1533, 2851, 2337, 1746, 2944, 2701, 137,
+ 628, 2838, 2157, 2456, 2519, 2391, 559, 961, 2962, 2378, 2727, 2841, 2200, 2701,
+ 1966, 2210, 2996, 2654, 1583, 2875, 2890, 2923, 2135, 2743, 2672, 86, 2986, 2691,
+ 2984, 2699, 2869, 179, 2419, 1993, 1523, 1378, 2696, 2188, 1774, 2330, 2582, 1958,
+ 2541, 2903, 3004, 487, 793, 2820, 2438, 2131, 1846, 2751, 3007, 21, 2102, 2128,
+ 614, 794, 3034, 129, 2965, 2963, 2474, 2575, 2850, 2659, 3024, 2553, 1912, 3048,
+ 2991, 754, 1039, 1208, 2939, 1302, 1746, 2418, 1473, 3058, 2931, 3060, 2368, 37,
+ 3021, 1483, 2941, 2676, 422, 1775,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 0;
+ let segment_n = 3;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 1994, 1933, 3035, 2492, 2197, 748, 349, 140, 1121, 3079, 2168, 1970, 2197, 2830,
+ 1473, 2995, 827, 3087, 2246, 3046, 46, 3067, 1420, 1484, 3062, 2612, 2122, 2360,
+ 3011, 1097, 1455, 2069, 2660, 3103, 574, 1665, 3086, 2750, 3101, 1391, 2770, 3013,
+ 1691, 2929, 2411, 1272, 1296, 811, 2499, 3064, 2675, 2926, 212, 399, 1439, 2894,
+ 2697, 1881, 2007, 2706, 3130, 3046, 1253, 1722, 2461, 3023, 3128, 2093, 2757, 897,
+ 3057, 1176, 2290, 1336, 3108, 3145, 1445, 2613, 3133, 2501, 1305, 1654, 851, 2608,
+ 2289, 1673, 1057, 1657, 140, 2399, 419, 2186, 3033, 3161, 3115, 2430, 2574, 1914,
+ 2974, 3134, 2458, 3073, 2879, 226, 2871, 2926, 1917, 3015, 3147, 3030, 2852, 1399,
+ 878, 1885, 3182, 217, 3110, 1513, 1933, 1628, 3169, 220, 1147, 3116, 3010, 438,
+ 2263, 2382, 2443, 440, 2907, 404, 2897, 68, 2020, 2815, 3096, 3169, 3144, 1401,
+ 3029, 1072, 33, 663, 890, 2932, 3200, 3096, 628, 1371, 3096, 1851, 1144, 365, 2097,
+ 2344, 974, 978, 2558, 135, 3055, 446, 1128, 2599, 1680, 255, 2191, 1603, 1025,
+ 1842, 2017, 517, 3210, 3170, 966, 790, 811, 2253, 2222, 1163, 1933, 2902, 762, 546,
+ 3219, 198, 1729, 1650, 3208, 1435, 2689, 1729, 3113, 2222, 3206, 2918, 584, 829,
+ 2437, 3113, 2805, 2742, 3172, 2823, 356, 716, 1895, 2369, 2268, 3255, 2981, 2733,
+ 903, 1945, 1593, 553, 32, 3105, 1759, 238, 1154, 2399, 2691, 480, 2571, 3285, 3211,
+ 959, 1936, 2767, 2697, 375, 2833, 3264, 2837, 3305, 2938, 3284, 1696, 801, 485,
+ 1911, 3282, 3221, 1002, 876, 18, 1589, 2416, 3304, 160, 3097, 1387, 3074, 3322,
+ 3012, 3209, 2100, 1419, 2621, 2667, 856, 1981, 1456, 1902, 1690, 1318, 2344, 620,
+ 1141, 2449, 3063, 2904, 2311, 2441, 2419, 1166, 1786, 3338, 563, 3266, 2275, 2559,
+ 3352, 3352, 2638, 1635, 1671, 2322, 2914, 3333, 2832, 2522, 3050, 2184, 3045, 1692,
+ 474, 293, 803, 3271, 3192, 1902, 3363, 3094, 221, 2809, 3030, 791, 2951, 1791,
+ 3242, 3202, 2124, 1579, 1782, 2476, 1695, 2817, 2673, 1016, 1265, 2231, 1911, 3335,
+ 228, 303, 1179, 1439, 1720, 3400, 2533, 2439, 3355, 2596, 3061, 119, 318, 2476,
+ 1347, 3194, 2759, 1670, 2601, 3399, 1707, 3046, 2575, 2810, 2234, 2321, 1292, 1207,
+ 3409, 2350, 3237, 2156, 3385, 3286, 2872, 2743, 1195, 1246, 972, 1649, 996, 3093,
+ 2833, 3340, 3171, 1957, 3304, 908, 3431, 819, 322, 3212, 3077, 1972, 2919, 2679,
+ 2408, 2521, 2940, 2055, 3429, 2653, 2908, 1868, 2689, 3100, 3389, 2094, 1810, 3278,
+ 2796, 2819, 3052, 2430, 2080, 3464, 3150, 2448, 3084, 60, 2216, 1493, 3163, 3335,
+ 2886, 914, 1603, 3429, 3468, 3226, 2832, 2990, 3471, 483, 2746, 3181, 943, 547,
+ 1556, 778, 2143, 2401, 2108, 586, 3425, 320, 2811, 3501, 3326, 1887, 3444, 876,
+ 1612, 664, 2896, 907, 3438, 2041, 1891, 954, 3231, 640, 734, 3458, 2878, 3408, 621,
+ 3011, 2434, 770, 2784, 760, 3226, 3505, 251, 3070, 2046, 95, 513, 2968, 3523, 3353,
+ 1673, 2599, 2740, 495, 3515, 1649, 3542, 3105, 3535, 2339, 2537, 2100, 732, 3512,
+ 2167, 3480, 3016, 1366, 868, 3386, 711, 1839, 3403, 3439, 2795, 3535, 1514, 1629,
+ 2180, 3228, 2149, 3422, 3485, 2052, 3482, 320, 3069, 1410, 1403, 1091, 3257, 3173,
+ 1376, 2807, 2799, 208, 1410, 1003, 1733, 695, 3398, 619, 3549, 1557, 3422, 190,
+ 1925, 2222, 2676, 3523, 3086, 2714, 3131, 1158, 993, 3381, 1871, 193, 3442, 671,
+ 3583, 2495, 3288, 3398, 2887, 3159, 1794, 2334, 3606, 3573, 2011, 1480, 2701, 2231,
+ 3613, 3588, 2949, 1926, 3005, 3621, 2029, 415, 2734, 43, 1361, 3358, 3574, 3398,
+ 3247, 3378, 632, 2396, 1477, 3174, 222, 1372, 1804, 3267, 1834, 2155, 360, 3350,
+ 2856, 2645, 3089, 23, 3508, 3648, 999, 3100, 2664, 3467, 1482, 3534, 2781, 3150,
+ 2638, 3191, 1524, 2977, 3125, 851, 1556, 2222, 3669, 1880, 722, 953, 1260, 3638,
+ 3533, 3430, 3478, 2298, 3458, 2906, 3654, 2653, 2603, 2776, 1028, 3002, 328, 2747,
+ 2779, 1072, 3184, 3554, 3374, 3156, 1384, 3100, 3346, 1729, 1349, 3615, 3697, 3535,
+ 2686, 3610, 2074, 230, 37, 1497, 3489, 3384, 1671, 2232, 1013, 1453, 3649, 1058,
+ 3243, 3550, 177, 96, 604, 821, 633, 3287, 3320, 2220, 413, 3709, 3326, 2402, 3294,
+ 2790, 2368, 1661, 3308, 2701, 3725, 3330, 1705, 2927, 1502, 1837, 1100, 3746, 654,
+ 3319, 218, 1922, 3680, 1232, 3597, 860, 2108, 2154, 1082, 1995, 3753, 3462, 2466,
+ 318, 1409, 3764, 2731, 3603, 2844, 3757, 2056, 2602, 3741, 1681, 800, 3723, 2870,
+ 3288, 2446, 2389, 3004, 3604, 3682, 3142, 3039, 3630, 1750, 1344, 3730, 1941, 2803,
+ 2550, 2626, 3777, 762, 497, 3359, 2122, 3429, 600, 826, 3588, 3500, 1739, 3711,
+ 3676, 3399, 3402, 3466, 2549, 2556, 2734, 1176, 3757, 470, 1921, 3746, 3799, 563,
+ 2833, 2446, 1317, 3522, 227, 3672, 3260, 3470, 3410, 1927, 2243, 3316, 2320, 635,
+ 2812, 1504, 3785, 3228, 304, 2769, 311, 3367, 3392, 3726, 3816, 2705, 2129, 2989,
+ 335, 3833, 405, 2941, 2889, 3733, 3023, 2587, 3210, 3233, 3673, 2309, 2814, 3251,
+ 3150, 3496, 3169, 2995, 2407, 3712, 360, 3826, 3247, 2686, 2504, 3338, 3642, 2022,
+ 3774, 3508, 3792, 2212, 3797, 3778, 3715, 2145, 2512, 3171, 1064, 2584, 3869, 3585,
+ 3851, 3735, 738, 3848, 3254, 3886, 3672, 1251, 3138, 3453, 3143, 3619, 908, 2126,
+ 1793, 2885, 3848, 1124, 371, 2480, 2259, 847, 2984, 1946, 2711, 895, 3895, 3913,
+ 606, 3555, 3842, 3282, 2123, 3518, 3750, 2224, 2785, 3325, 2308, 3635, 886, 3620,
+ 3155, 3829, 2319, 3874, 2562, 2655, 3836, 46, 314, 3848, 3751, 2409, 2931, 1999,
+ 2616, 3702, 109, 84, 1304, 1813, 3010, 3349, 3821, 3408, 3952, 3328, 3799, 2967,
+ 3035, 3648, 2474, 1687, 1279, 3947, 2466, 1357, 3900, 3549, 1002, 2750, 2986, 3379,
+ 1172, 3133, 534, 3210, 3414, 2426, 3883, 3862, 3752, 2932, 1354, 3897, 1874, 2831,
+ 2539, 2703, 758, 3975, 3144, 2367, 1233, 3797, 1662, 593, 3642, 2411, 2952, 337,
+ 2414, 3672, 3025, 2729, 1912, 2480, 3965, 3085, 3863, 1709, 3944, 1021, 542, 1782,
+ 1727, 3879, 2812, 3276, 4018, 3267, 3672, 1016, 3486, 3657, 3735, 516, 3565, 3432,
+ 2371, 2634, 2072, 551, 2391, 2460, 3462, 787, 4015, 1804, 2544, 3707, 3879, 2939,
+ 3612, 861, 2213, 3021, 3818, 3902, 3944, 4045, 3272, 1861, 747, 3224, 4054, 3263,
+ 1623, 2018, 1460, 2158, 1170, 88, 1537, 3542, 1722, 4012, 1630, 3058, 2203, 2610,
+ 4059, 3730, 2042, 1090, 199, 1907, 3848, 3983, 3810, 3603, 1068, 3985, 2454, 3950,
+ 1163, 1752, 3677, 1553, 2352, 3650, 1758, 1756, 3893, 3566,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 1;
+ let segment_n = 0;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 3988, 3490, 1643, 1572, 2, 2045, 1188, 3185, 1866, 1635, 3419, 1196, 3779, 2875,
+ 2786, 3906, 3086, 2300, 3, 3715, 3942, 3921, 4060, 3970, 22, 4095, 23, 11, 2880, 1,
+ 3617, 3244, 3935, 3222, 2814, 1706, 3349, 3372, 34, 1984, 1488, 3332, 3582, 3950,
+ 2803, 3986, 2228, 3844, 1767, 3772, 43, 3307, 3131, 3811, 3437, 3530, 2226, 4093,
+ 3934, 3401, 2948, 59, 4067, 3888, 32, 1302, 3233, 3650, 2178, 2376, 3271, 4094,
+ 2467, 2975, 3512, 3452, 3074, 3034, 57, 2174, 2062, 4072, 3086, 3175, 3988, 1343,
+ 48, 3438, 3295, 87, 1844, 4004, 3389, 46, 2672, 3108, 3065, 2149, 3720, 4057, 84,
+ 2027, 2275, 2567, 1600, 2653, 1444, 2508, 63, 3744, 1255, 3175, 49, 2728, 3522, 34,
+ 3046, 3728, 115, 1199, 2500, 3337, 96, 108, 28, 3502, 1317, 3739, 3318, 112, 4079,
+ 2308, 2026, 1040, 121, 2328, 3084, 56, 4088, 2008, 2194, 116, 1140, 2896, 135, 132,
+ 144, 2501, 143, 147, 3817, 2696, 2858, 3652, 3507, 19, 2382, 3342, 3957, 2451,
+ 3434, 1282, 1549, 4005, 3990, 3881, 2381, 3239, 2745, 2168, 2493, 4073, 3910, 109,
+ 110, 2368, 3030, 3839, 3248, 3830, 3761, 46, 3449, 70, 156, 2833, 2515, 3655, 2023,
+ 39, 3344, 180, 2053, 1684, 2909, 2463, 3773, 3520, 3941, 197, 3686, 4025, 192,
+ 2798, 202, 3435, 2350, 3632, 3295, 1999, 153, 2793, 3683, 209, 152, 1262, 2850,
+ 1430, 4028, 3260, 2211, 1700, 3592, 1209, 3571, 2943, 90, 3266, 3022, 3878, 218,
+ 1718, 8, 1771, 229, 229, 2940, 2986, 2155, 2464, 2345, 102, 1974, 3434, 1860, 3667,
+ 119, 245, 2392, 152, 1126, 3593, 3527, 3949, 2743, 2701, 3953, 3002, 221, 3610,
+ 2928, 1918, 1094, 261, 262, 3229, 3836, 24, 3257, 3270, 1076, 5, 2958, 3003, 4039,
+ 148, 2097, 2706, 3959, 3262, 3022, 3132, 56, 6, 1700, 162, 2764, 3144, 1230, 1445,
+ 1070, 3603, 4004, 3432, 282, 1736, 2961, 1993, 3222, 2212, 3370, 291, 268, 1639,
+ 3939, 2905, 1712, 1069, 1272, 3834, 2070, 286, 3625, 279, 3301, 3454, 162, 305,
+ 227, 302, 3646, 313, 3865, 1087, 2241, 1663, 4019, 1606, 326, 2658, 3750, 2135,
+ 328, 235, 2500, 2800, 279, 2614, 2567, 58, 37, 4069, 47, 3206, 342, 188, 2918,
+ 3825, 3460, 1495, 3265, 4031, 2745, 2380, 165, 278, 3606, 1443, 3855, 315, 2342,
+ 359, 303, 3392, 362, 3452, 2982, 3839, 1608, 1459, 2650, 368, 1814, 2275, 3642,
+ 2952, 369, 3927, 3159, 1622, 360, 334, 3930, 3472, 138, 3185, 374, 222, 3100, 1798,
+ 2777, 1706, 2917, 2649, 2096, 266, 394, 1427, 3497, 1292, 2206, 392, 2694, 1707,
+ 3555, 3896, 3302, 1105, 406, 406, 2399, 2411, 3565, 3063, 3925, 3997, 3725, 1447,
+ 318, 3664, 416, 2251, 131, 2895, 2403, 1350, 1749, 16, 426, 4019, 3332, 4018, 411,
+ 280, 2228, 3016, 3934, 435, 1872, 3959, 2684, 342, 1162, 2587, 3788, 4026, 353,
+ 400, 339, 2291, 413, 4077, 184, 4033, 3671, 346, 4048, 1047, 3619, 166, 3494, 2644,
+ 279, 2239, 456, 442, 322, 3818, 161, 1896, 3253, 438, 3402, 3643, 3521, 3839, 2954,
+ 203, 3217, 1807, 452, 3231, 4003, 2726, 181, 3880, 3289, 1694, 446, 474, 427, 66,
+ 1619, 2430, 3377, 3705, 2047, 472, 369, 120, 494, 2756, 2091, 180, 10, 1508, 1795,
+ 3633, 144, 337, 4051, 502, 3416, 504, 436, 1117, 3587, 3623, 2741, 3494, 502, 2813,
+ 115, 3231, 2974, 2351, 2250, 4063, 515, 502, 3553, 199, 1882, 3927, 2514, 3087,
+ 2321, 450, 92, 1073, 2338, 2016, 2364, 1586, 1697, 1759, 1708, 3172, 1211, 407,
+ 163, 3202, 501, 1832, 3385, 545, 4057, 215, 65, 1148, 3082, 3788, 500, 310, 2162,
+ 446, 1207, 384, 2331, 3702, 3438, 2386, 2511, 2751, 2311, 4016, 4038, 565, 2123,
+ 4005, 3441, 413, 2705, 349, 570, 2292, 568, 1324, 1481, 3874, 550, 545, 582, 3371,
+ 215, 592, 3841, 2807, 3537, 524, 1897, 1714, 3159, 596, 364, 1889, 3933, 457, 1317,
+ 2543, 1213, 2658, 181, 444, 2997, 3926, 1768, 1966, 1384, 3599, 3968, 433, 304,
+ 2624, 3085, 606, 3968, 1620, 114, 244, 441, 2426, 34, 2765, 2370, 4076, 3540, 438,
+ 602, 2860, 1727, 3750, 3888, 3848, 1457, 1851, 3201, 3435, 1397, 240, 3450, 4032,
+ 210, 2774, 3939, 650, 437, 315, 1374, 2614, 181, 1900, 2323, 2730, 3691, 2968, 486,
+ 636, 2549, 2433, 204, 268, 139, 2891, 572, 659, 3636, 568, 3588, 673, 665, 571,
+ 1273, 656, 1522, 3774, 433, 1740, 1225, 3837, 3810, 203, 2764, 466, 2456, 548,
+ 3811, 658, 647, 553, 3606, 548, 673, 3231, 253, 135, 16, 156, 2521, 3477, 108,
+ 2448, 670, 1430, 346, 616, 3352, 1418, 248, 2283, 717, 3306, 2386, 480, 1873, 2910,
+ 724, 2143, 557, 3569, 386, 2504, 728, 2769, 727, 2801, 501, 90, 680, 3921, 1721,
+ 711, 560, 1235, 52, 1741, 2917, 1716, 585, 744, 604, 73, 571, 338, 2417, 127, 1412,
+ 4086, 120, 686, 2937, 1667, 2503, 491, 754, 3941, 2376, 762, 737, 259, 528, 3686,
+ 3771, 1717, 761, 3968, 2662, 40, 1719, 775, 665, 4008, 706, 1365, 3115, 89, 2193,
+ 1136, 2328, 471, 2329, 638, 590, 66, 3378, 312, 3487, 324, 645, 639, 3706, 3909,
+ 4036, 1542, 692, 2490, 3814, 800, 15, 2687, 4077, 1627, 786, 568, 593, 3966, 3956,
+ 638, 2024, 733, 2862, 2482, 1728, 95, 613, 158, 793, 568, 3619, 55, 2964, 3020,
+ 794, 2147, 460, 3180, 1459, 309, 2983, 443, 3010, 3695, 2593, 790, 807, 1633, 843,
+ 361, 3141, 324, 499, 309, 43, 3856, 2354, 1853, 591, 1151, 687, 582, 1525, 1594,
+ 2164, 265, 421, 2592, 2636, 2356, 361, 834, 35, 2267, 3114, 3425, 1689, 2024, 857,
+ 1159, 3108, 195, 3849, 2516, 181, 202, 874, 2371, 774, 1535, 711, 794, 2686, 2642,
+ 3781, 2184, 1333, 2807, 524, 2409, 4083, 2988, 887, 864, 70, 3995, 3267, 1877,
+ 3963, 3247, 1600, 596, 307, 2273, 1344, 910, 475, 736, 2561, 304, 2636, 915, 2689,
+ 654, 1941, 1125, 2766, 461, 2247, 916, 3780, 3677, 454, 877, 3423, 842, 2621, 3791,
+ 50, 380, 3101, 844, 2594, 1216, 1812, 767, 888, 3541, 690, 233, 3272, 1511, 851,
+ 161, 767, 3583, 755, 1448, 1633, 907, 3078, 3961, 2910, 955, 3204, 1975, 1842, 817,
+ 2869, 1668, 779, 3339, 552, 969, 1058, 766, 955, 1722, 4014, 519, 2975, 1459, 874,
+ 2952, 947, 979, 1933, 2478, 665, 985, 982, 815, 21, 1179, 3217, 1056, 129, 815,
+ 1508, 739, 3801, 982, 768, 4038, 1788, 2571, 999, 2494, 3683, 1257, 1003, 751,
+ 4079, 1009, 184, 91, 3936, 1790, 3997, 719, 1012, 3540, 3910, 848, 980, 726,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 1;
+ let segment_n = 1;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 3423, 3780, 3751, 584, 2089, 3394, 594, 952, 3177, 3537, 2536, 2720, 3812, 1004,
+ 795, 353, 487, 27, 458, 566, 404, 3545, 945, 998, 3517, 1047, 4008, 448, 515, 999,
+ 1048, 939, 277, 2497, 89, 2786, 989, 420, 3571, 384, 740, 331, 2268, 2791, 843,
+ 518, 2447, 3880, 918, 3041, 3534, 385, 134, 3210, 2690, 3631, 3050, 839, 358, 1062,
+ 2949, 910, 537, 874, 2462, 3775, 842, 1083, 1063, 3225, 3141, 944, 971, 2956, 4004,
+ 1030, 178, 850, 2505, 3374, 474, 2961, 20, 3616, 3197, 1028, 2236, 290, 851, 561,
+ 934, 914, 260, 235, 1078, 931, 94, 2329, 593, 717, 2290, 869, 555, 368, 644, 3422,
+ 822, 3169, 1105, 21, 2107, 1109, 803, 1123, 1135, 184, 4070, 661, 3376, 853, 2888,
+ 3867, 1072, 1128, 965, 2138, 1119, 186, 405, 2561, 3857, 481, 2208, 287, 1137,
+ 2389, 132, 646, 627, 1128, 4051, 1030, 2679, 123, 63, 1120, 3701, 1135, 1166, 4029,
+ 2725, 1173, 2213, 2216, 465, 986, 303, 983, 846, 1069, 1096, 1172, 324, 1071, 718,
+ 486, 1110, 1166, 1063, 276, 1081, 3791, 2574, 180, 3812, 825, 2481, 586, 2292,
+ 2777, 2725, 3779, 748, 92, 1193, 1007, 3302, 568, 2694, 255, 993, 897, 3676, 226,
+ 1104, 2778, 2121, 1201, 1064, 2908, 1195, 1223, 1092, 3153, 3966, 1227, 3241, 1228,
+ 3771, 1163, 1232, 5, 989, 3734, 3190, 1138, 1101, 3105, 1118, 3935, 1122, 787,
+ 2214, 2745, 913, 832, 769, 651, 3543, 3967, 406, 2304, 4031, 961, 3660, 1256, 335,
+ 2970, 2273, 3860, 3150, 1180, 2498, 974, 966, 3133, 652, 336, 735, 439, 3049, 1273,
+ 3191, 3631, 875, 1272, 1277, 3960, 1232, 2577, 637, 765, 2972, 737, 3569, 991,
+ 2892, 3886, 2767, 3809, 834, 1278, 630, 1173, 1090, 1152, 3560, 426, 1189, 1266,
+ 3572, 834, 956, 953, 1303, 475, 3508, 1293, 3134, 816, 2764, 2537, 1314, 3700,
+ 1261, 1317, 1176, 460, 978, 1003, 1282, 1323, 3823, 651, 674, 957, 2390, 3299, 857,
+ 4075, 3598, 1097, 1318, 1281, 3369, 4002, 1048, 1223, 1154, 1201, 591, 589, 1280,
+ 345, 353, 3883, 381, 348, 3228, 969, 2067, 2092, 2454, 2600, 147, 61, 608, 1134,
+ 356, 945, 1230, 475, 1075, 793, 2229, 908, 3184, 3554, 334, 1324, 2059, 1373, 1163,
+ 2796, 1274, 2943, 1377, 3114, 3960, 493, 3433, 3792, 1107, 3051, 2727, 3814, 1139,
+ 1150, 2592, 1016, 1013, 2566, 2993, 1367, 3031, 919, 664, 1344, 3670, 3018, 1382,
+ 348, 1080, 3092, 704, 924, 1370, 289, 4084, 1219, 487, 3658, 3809, 2875, 1096,
+ 1276, 211, 1227, 3640, 1305, 3344, 708, 2950, 1133, 563, 339, 1355, 1429, 704,
+ 3219, 1405, 1408, 3986, 1047, 189, 1198, 798, 1408, 430, 301, 1292, 1373, 3113,
+ 2234, 1396, 707, 271, 1218, 375, 1278, 596, 788, 477, 867, 2050, 1135, 1350, 1248,
+ 3662, 2118, 3123, 2568, 1250, 304, 461, 3974, 1095, 2358, 307, 2605, 1155, 1042,
+ 1310, 439, 1441, 3956, 3397, 2696, 377, 1159, 2307, 97, 461, 1141, 57, 660, 2627,
+ 355, 2825, 911, 1271, 3072, 2283, 165, 1445, 1497, 467, 1477, 767, 3004, 380, 3583,
+ 1008, 3091, 138, 3099, 501, 998, 3858, 1269, 3670, 1436, 898, 1272, 3119, 611,
+ 2150, 2508, 1294, 32, 1516, 3579, 1332, 1524, 2509, 745, 678, 878, 1513, 2944,
+ 1302, 1259, 3425, 1509, 1534, 1537, 1151, 3462, 867, 889, 2804, 859, 4019, 1041,
+ 1008, 1066, 1225, 2697, 1529, 3659, 905, 1025, 22, 2701, 1172, 2802, 3831, 211,
+ 3590, 288, 993, 288, 2970, 1425, 1295, 3629, 849, 1116, 1403, 1248, 1572, 1521, 55,
+ 1570, 1234, 1269, 1560, 2831, 3335, 1336, 2891, 191, 73, 807, 619, 1339, 1283,
+ 2525, 1587, 3490, 1413, 692, 734, 1229, 1541, 3022, 1395, 1482, 836, 2965, 1030,
+ 4039, 1586, 2197, 661, 1512, 3183, 2061, 2611, 4078, 1572, 2220, 1614, 383, 1488,
+ 1442, 1618, 3842, 617, 716, 3901, 1623, 2467, 1230, 3782, 197, 2217, 264, 2443,
+ 1217, 950, 2971, 713, 1054, 3040, 1060, 299, 4040, 1472, 1439, 1387, 3819, 724,
+ 524, 2224, 1625, 1530, 2646, 1506, 782, 30, 2640, 1385, 1651, 2720, 433, 1194,
+ 1573, 1423, 1661, 487, 1284, 1598, 1382, 1273, 3468, 1015, 2545, 3891, 1563, 1655,
+ 836, 1298, 1066, 2554, 336, 3767, 1212, 3388, 3602, 884, 698, 2443, 1350, 194,
+ 1030, 846, 2706, 1590, 51, 745, 1528, 1466, 1069, 569, 2592, 1349, 1321, 4042,
+ 1089, 3904, 1492, 3710, 3268, 2899, 504, 1513, 3313, 3066, 3315, 1066, 1441, 1374,
+ 831, 2758, 776, 1711, 1546, 1657, 1182, 1699, 200, 1665, 4007, 734, 1605, 1725,
+ 1480, 8, 1544, 3834, 1717, 1697, 2960, 1654, 1420, 987, 89, 1352, 380, 2300, 1589,
+ 193, 3457, 1536, 1710, 1260, 3183, 1408, 1205, 38, 1726, 465, 711, 1181, 303, 1703,
+ 3837, 1343, 3576, 2656, 3250, 1001, 3675, 1353, 2677, 156, 4062, 99, 693, 2337,
+ 271, 3933, 2452, 183, 2611, 3123, 1746, 727, 1146, 554, 2827, 1784, 3763, 3486,
+ 520, 3369, 676, 758, 3872, 1261, 3440, 1268, 710, 2928, 4016, 1572, 1425, 2108,
+ 1333, 1632, 2949, 2341, 648, 1777, 3100, 1719, 1491, 654, 1634, 887, 517, 1789,
+ 1179, 1780, 131, 1788, 1278, 1820, 3597, 3244, 3527, 701, 1460, 3122, 4014, 687,
+ 3583, 1824, 1445, 1479, 1825, 1609, 1200, 3708, 2330, 3749, 2597, 487, 1421, 1405,
+ 2865, 1637, 230, 1086, 2748, 899, 1693, 1815, 1840, 4084, 1837, 1804, 2474, 1802,
+ 1192, 3934, 220, 3029, 1732, 461, 1828, 486, 2251, 922, 1867, 1353, 476, 503, 339,
+ 1808, 1823, 874, 2751, 1866, 3880, 1792, 37, 3212, 1309, 1479, 146, 3790, 290,
+ 1882, 2349, 1884, 1870, 1889, 1872, 1105, 1206, 1525, 2595, 687, 1261, 1826, 1740,
+ 1791, 1851, 3759, 3588, 1389, 1664, 1783, 26, 1626, 2808, 1840, 3685, 746, 1265,
+ 3869, 2599, 1495, 310, 1307, 1611, 1390, 234, 2423, 1912, 3334, 1361, 4074, 45,
+ 2171, 1891, 1726, 804, 1506, 3422, 1678, 1720, 1909, 1779, 3583, 718, 1551, 1800,
+ 1662, 1733, 1571, 1631, 1175, 1492, 1760, 2327, 2943, 1721, 3728, 1597, 1034, 991,
+ 153, 3318, 238, 807, 1270, 2344, 1846, 3776, 781, 332, 1622, 344, 3123, 246, 2578,
+ 185, 35, 1953, 1727, 2469, 2365, 757, 1960, 1257, 4041, 2354, 944, 362, 1848, 160,
+ 2763, 2290, 2289, 1866, 1805, 1615, 1929, 3689, 1658, 3432, 399, 3833, 246, 2218,
+ 1694, 3069, 1447, 2312, 1997, 1423, 1484, 1795, 2003, 303, 1688, 452, 631, 1006,
+ 3922, 3495, 3408, 3505, 1469, 3679, 1390, 185, 1848, 1999, 3947, 835, 1703, 1068,
+ 2140, 2319, 13, 3447, 3743, 3946, 345, 237, 1944, 929, 1616, 3037, 1789, 1760,
+ 2035, 2712, 3411, 1658,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 1;
+ let segment_n = 2;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 1513, 2045, 1126, 245, 3943, 2044, 513, 1861, 1947, 1963, 2051, 1644, 1154, 1569,
+ 1920, 1869, 2013, 1470, 2044, 406, 1797, 2023, 2060, 1863, 1686, 3886, 1888, 1995,
+ 428, 940, 3907, 2071, 1058, 3602, 349, 863, 1968, 1221, 557, 1582, 944, 1583, 2088,
+ 1142, 853, 107, 2057, 1991, 3307, 1401, 451, 1164, 889, 1924, 1462, 2081, 3412,
+ 2103, 506, 803, 1961, 4062, 185, 1296, 1534, 16, 2100, 1768, 1941, 277, 3997, 1009,
+ 387, 1785, 1396, 1628, 2113, 3422, 2122, 1218, 615, 2127, 1743, 2095, 948, 3469,
+ 647, 543, 1923, 135, 1474, 1126, 2124, 924, 2140, 2115, 1123, 482, 1441, 1478,
+ 1546, 4076, 1818, 2020, 1720, 1933, 1841, 2153, 2154, 1811, 1370, 2066, 1362, 2031,
+ 2152, 2095, 1788, 2163, 2080, 2077, 2119, 1220, 859, 1921, 1940, 1830, 1761, 1347,
+ 645, 3286, 1196, 976, 1664, 2098, 1600, 1185, 1811, 1718, 1581, 1079, 2101, 1820,
+ 3408, 1714, 1979, 1774, 3723, 2180, 764, 706, 1467, 2003, 428, 575, 2070, 1566,
+ 1824, 295, 1333, 2185, 877, 527, 889, 1473, 3166, 2064, 2190, 1681, 1529, 3957,
+ 2214, 1479, 294, 4051, 1063, 1418, 2112, 3085, 768, 1651, 3359, 205, 1911, 2026,
+ 622, 325, 1877, 2172, 2195, 3758, 1028, 1937, 3589, 2088, 1583, 2172, 3657, 1075,
+ 2229, 701, 1655, 2247, 60, 3949, 1936, 1145, 380, 2082, 3785, 3366, 1363, 3509,
+ 989, 2185, 3289, 355, 2067, 2248, 3467, 2237, 1156, 2264, 2044, 2042, 2016, 362,
+ 1417, 2035, 2092, 1935, 572, 190, 3761, 1993, 1514, 315, 1406, 2282, 2216, 2192,
+ 3292, 1234, 442, 2257, 2219, 1875, 3399, 4092, 3126, 3610, 682, 1565, 2077, 2180,
+ 1416, 1854, 2293, 2288, 2232, 2001, 104, 2262, 887, 1954, 2281, 3947, 244, 1339,
+ 1474, 571, 2300, 287, 1803, 1868, 492, 1943, 4077, 3227, 511, 2206, 3179, 3779,
+ 3668, 1438, 1246, 1194, 1953, 1937, 2333, 1797, 2316, 2011, 1234, 3784, 2210, 1814,
+ 621, 1047, 3893, 2036, 345, 3745, 819, 2326, 2338, 889, 1928, 935, 1957, 3157, 569,
+ 728, 2219, 3279, 1156, 1934, 324, 635, 2131, 2314, 3740, 2348, 1824, 2008, 645,
+ 2269, 2354, 3085, 1653, 3497, 585, 701, 3604, 3798, 1801, 3229, 533, 4, 1676, 1781,
+ 4088, 1897, 1803, 2316, 2150, 2045, 1951, 1958, 2079, 849, 3774, 1300, 2354, 2134,
+ 1313, 2227, 2101, 2198, 116, 2400, 110, 2143, 764, 468, 2042, 3435, 2374, 2236,
+ 1323, 956, 1738, 1775, 10, 2064, 1931, 2267, 1383, 2291, 3468, 3500, 3210, 249,
+ 2428, 1463, 1847, 2426, 1754, 2324, 1683, 1462, 2361, 1508, 1870, 660, 2440, 2363,
+ 1455, 1002, 2430, 3263, 876, 3896, 3698, 1960, 2417, 178, 1203, 3587, 883, 2090,
+ 2430, 2252, 285, 3825, 2383, 2395, 2389, 3183, 2199, 381, 262, 2466, 2463, 167,
+ 1462, 1741, 1183, 1357, 837, 2458, 2267, 3893, 2453, 631, 2427, 1576, 1366, 1468,
+ 534, 1315, 2317, 3613, 2466, 3995, 1715, 3409, 1110, 3513, 2191, 2158, 1674, 2429,
+ 2007, 1926, 2421, 2490, 3496, 1740, 2483, 34, 1103, 1845, 1313, 3405, 3538, 2073,
+ 2512, 2299, 279, 2389, 2303, 1221, 352, 2519, 2454, 3118, 2479, 2519, 1664, 2205,
+ 524, 2009, 3915, 2485, 2332, 593, 2327, 2363, 3715, 2099, 2507, 1092, 1994, 2263,
+ 2341, 2370, 1126, 1628, 2535, 252, 773, 3748, 2547, 711, 2025, 1273, 323, 3187,
+ 1140, 620, 2517, 1221, 3710, 2058, 3398, 2357, 2119, 1424, 3824, 875, 741, 1247,
+ 3244, 2568, 568, 2277, 2570, 905, 2255, 124, 1658, 1680, 1060, 3235, 3820, 308,
+ 932, 1301, 343, 2554, 361, 2358, 2559, 2589, 2416, 2591, 2553, 1777, 2470, 1277,
+ 2589, 1888, 2531, 263, 1292, 1961, 2079, 2597, 1948, 2603, 3547, 193, 1748, 2545,
+ 2553, 1079, 1147, 3603, 592, 4033, 18, 2467, 1665, 2554, 2582, 2528, 1789, 1964,
+ 3765, 1414, 470, 2342, 1653, 2572, 1128, 3388, 2542, 723, 903, 2594, 2122, 2376,
+ 1666, 2566, 2637, 3476, 3818, 2618, 2188, 3996, 2600, 549, 1600, 960, 3146, 2377,
+ 2650, 1152, 3394, 2569, 1943, 2275, 2627, 3707, 2651, 3554, 972, 2556, 1917, 2636,
+ 1191, 3930, 1159, 1016, 765, 1944, 1424, 745, 3832, 2664, 102, 3179, 2608, 2469,
+ 1789, 3197, 3877, 1494, 2681, 2461, 805, 2594, 1643, 2397, 3751, 1717, 2515, 2550,
+ 2554, 1179, 2696, 2373, 1801, 3136, 2700, 87, 2606, 428, 34, 3817, 2311, 3668,
+ 2464, 2466, 2083, 1214, 2009, 849, 2714, 2119, 3726, 2703, 3685, 2599, 1364, 2509,
+ 2601, 2544, 3525, 1573, 1414, 1405, 2418, 2667, 1536, 64, 332, 1373, 930, 2067,
+ 2006, 304, 3259, 2227, 1821, 2718, 2649, 2721, 2026, 3998, 3552, 2021, 2742, 2236,
+ 2693, 3594, 2487, 1927, 2480, 563, 3090, 1812, 2548, 2061, 2758, 2490, 3, 455,
+ 1663, 3641, 1832, 2737, 945, 853, 2633, 1405, 1700, 2771, 2648, 2721, 2642, 3919,
+ 3837, 2488, 2669, 2393, 1373, 3511, 1129, 2602, 1648, 2595, 3852, 2679, 2281, 202,
+ 1579, 1665, 2643, 3787, 2739, 2746, 1737, 1736, 1922, 1602, 2303, 2151, 2722, 871,
+ 2767, 1178, 648, 1010, 2300, 2742, 2540, 779, 2703, 2805, 2589, 3297, 729, 731,
+ 1806, 2406, 3255, 2607, 614, 650, 844, 479, 3314, 3703, 3179, 609, 2776, 3164,
+ 1720, 634, 519, 2475, 1053, 1684, 589, 2564, 3687, 2836, 1908, 2330, 1396, 2840,
+ 2640, 2757, 1896, 19, 3919, 2825, 864, 48, 1554, 2345, 2474, 1751, 3898, 2391,
+ 2354, 775, 351, 2863, 2866, 682, 2160, 144, 2824, 2871, 2865, 1096, 1667, 469,
+ 2869, 306, 2642, 125, 2556, 2873, 2829, 2236, 683, 579, 1650, 2797, 2038, 2144,
+ 3779, 1848, 2398, 2719, 1223, 2751, 2848, 2529, 3195, 1749, 2407, 604, 2898, 1417,
+ 2804, 1883, 2735, 2774, 2781, 2869, 2632, 2595, 2912, 3259, 3475, 895, 531, 290,
+ 2918, 2710, 2655, 1254, 2407, 1924, 2746, 2560, 2903, 2729, 2837, 523, 1711, 2919,
+ 2887, 2627, 2867, 3430, 2089, 1121, 2391, 2408, 2850, 2349, 2863, 1617, 1443, 2931,
+ 4093, 1911, 3908, 2746, 1924, 1760, 3498, 1425, 3294, 1569, 1981, 792, 2313, 2954,
+ 2904, 396, 2850, 1309, 2060, 542, 703, 2184, 2259, 2629, 1993, 1000, 1350, 802,
+ 2896, 2746, 2778, 2729, 285, 155, 2676, 2685, 2960, 2941, 1617, 2585, 2833, 2913,
+ 2594, 1245, 3191, 674, 62, 355, 2382, 2194, 2441, 2077, 2907, 2418, 283, 2897,
+ 1010, 2228, 2991, 2811, 2852, 2468, 2998, 2942, 2627, 2164, 2111, 1737, 1688, 243,
+ 1557, 2043, 446, 3135, 381, 522, 2915, 2963, 2838, 2344, 2480, 3992, 1206, 3020,
+ 2327, 1195, 3303, 2923, 206, 3141, 2669, 2737, 1129, 2236, 2928, 2756, 1524, 3040,
+ 452, 1215, 2897, 2571, 2526, 2908, 2195, 2753, 3526, 2665, 2252, 2706, 1081, 3026,
+ 2313, 430, 3057, 2824, 2721, 1792, 1944, 3026, 3907, 2236, 978, 2126,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 1;
+ let segment_n = 3;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 1181, 2089, 2541, 1308, 2531, 2731, 2917, 2994, 551, 2431, 3080, 1148, 2328, 3025,
+ 2798, 2494, 2871, 1571, 1922, 2617, 910, 1553, 1431, 1393, 262, 2679, 3042, 2806,
+ 1705, 883, 137, 1122, 3070, 2945, 2562, 3096, 2991, 2326, 786, 3079, 2432, 562,
+ 2555, 2598, 1499, 1226, 3065, 841, 319, 3048, 371, 3094, 3100, 2390, 370, 2207,
+ 2965, 1263, 2574, 1478, 2992, 1602, 2749, 2480, 3108, 3135, 190, 1490, 1794, 502,
+ 2878, 3054, 469, 2726, 3111, 3135, 2708, 2488, 2699, 2598, 2097, 2631, 2615, 1710,
+ 1203, 148, 2686, 1136, 2669, 1542, 1789, 2185, 788, 1608, 2759, 3035, 2721, 1592,
+ 2730, 2750, 2154, 525, 3020, 2224, 3028, 1104, 3095, 1903, 438, 3179, 2980, 1683,
+ 820, 2727, 3166, 1192, 811, 703, 796, 3178, 334, 3191, 3138, 3117, 2580, 2410,
+ 1334, 2033, 1872, 1028, 435, 2089, 96, 3135, 2081, 377, 3126, 3204, 1227, 1744,
+ 3134, 2021, 2370, 470, 1334, 2745, 1739, 1230, 136, 60, 3099, 2613, 3172, 352,
+ 1599, 2530, 2382, 3198, 1797, 2601, 3083, 2540, 1784, 3233, 1357, 1989, 3234, 3044,
+ 2849, 2980, 3238, 2663, 3225, 3060, 610, 2598, 2001, 2497, 2161, 771, 1965, 2229,
+ 681, 3135, 2302, 3245, 2783, 2965, 449, 3125, 3199, 1739, 2975, 2936, 848, 3263,
+ 3256, 1013, 2491, 2039, 3238, 3220, 3117, 2029, 3265, 3192, 2672, 3168, 2584, 2329,
+ 626, 2430, 1362, 3281, 1974, 3048, 1302, 1880, 2898, 2833, 1854, 3277, 2615, 1466,
+ 1451, 1874, 2165, 3032, 2678, 3186, 2011, 3111, 1031, 571, 1823, 1165, 1568, 2635,
+ 3079, 1125, 2177, 3219, 426, 2283, 3296, 2767, 1524, 3267, 2556, 2508, 1996, 1072,
+ 1692, 3231, 3266, 3117, 2604, 3327, 2315, 3024, 1584, 1357, 3312, 1939, 2889, 1216,
+ 1509, 3152, 1231, 1371, 1710, 1549, 3253, 3268, 2725, 578, 3263, 3132, 50, 2647,
+ 1680, 3265, 2508, 2445, 3325, 2833, 1517, 3192, 1894, 3305, 1371, 1918, 2651, 1630,
+ 70, 934, 1676, 2348, 2400, 3218, 3278, 2631, 550, 94, 3014, 924, 3376, 1301, 2836,
+ 1051, 1477, 2888, 2105, 2346, 1844, 2052, 2859, 1735, 1429, 2436, 3047, 2856, 806,
+ 670, 3225, 624, 174, 1525, 3384, 3285, 2973, 2959, 3072, 2783, 3402, 3269, 1589,
+ 42, 2713, 856, 1843, 2265, 3379, 3079, 3004, 3405, 2636, 1782, 3416, 937, 3009,
+ 895, 2832, 1730, 3264, 3364, 3049, 3420, 1286, 2841, 3110, 2738, 3227, 3260, 3431,
+ 713, 3360, 2348, 1585, 3428, 3202, 1035, 3186, 2066, 145, 2814, 2684, 2836, 625,
+ 3420, 3371, 3418, 2395, 2766, 3454, 1403, 2782, 2102, 3430, 3339, 3436, 373, 54,
+ 2941, 3381, 916, 3453, 283, 3466, 2354, 773, 1781, 3452, 3333, 180, 368, 2057,
+ 1840, 3123, 3410, 3468, 2963, 3122, 3470, 1137, 1103, 391, 924, 2782, 1611, 2943,
+ 3489, 1682, 2538, 963, 2769, 1713, 2728, 2258, 3411, 2651, 317, 2177, 2610, 3005,
+ 3470, 3475, 3419, 3040, 2506, 3378, 1722, 623, 2415, 303, 165, 3516, 946, 1442,
+ 527, 3319, 3472, 2312, 3506, 1820, 3095, 3522, 3516, 2522, 2477, 577, 1423, 1026,
+ 758, 3299, 3154, 2818, 2883, 2111, 3209, 2107, 637, 2202, 3542, 1875, 1116, 3416,
+ 1776, 2639, 3452, 2668, 1398, 913, 2671, 3455, 1941, 3553, 386, 3521, 2064, 1071,
+ 1107, 3539, 236, 3253, 3511, 42, 3156, 784, 2774, 2412, 3014, 585, 600, 325, 1593,
+ 3561, 2343, 3430, 2507, 3509, 2925, 3438, 2295, 3361, 3583, 2748, 1078, 3580, 1964,
+ 2685, 206, 2447, 1745, 1724, 3257, 1607, 3506, 534, 1324, 1215, 2820, 2281, 1874,
+ 1541, 3600, 2775, 2684, 2275, 463, 975, 2529, 496, 792, 3295, 3237, 2407, 2908,
+ 1090, 1246, 821, 955, 1722, 1455, 3618, 3624, 680, 2559, 2107, 2102, 2024, 2809,
+ 2216, 3458, 3620, 3229, 3427, 3446, 3537, 2424, 2833, 3438, 3629, 1625, 1486, 58,
+ 3577, 3444, 1249, 2847, 3103, 1864, 2747, 1459, 2584, 3613, 1045, 157, 3606, 569,
+ 3558, 3602, 2711, 595, 1869, 3663, 3598, 3592, 3666, 3550, 2688, 1483, 3088, 3325,
+ 400, 2790, 1412, 850, 726, 3072, 277, 21, 1876, 3520, 2697, 2752, 2014, 3639, 1604,
+ 3506, 3643, 3691, 1467, 3264, 1647, 3625, 1591, 3195, 1432, 1967, 3700, 3563, 924,
+ 3342, 3566, 1130, 3502, 3689, 2209, 3524, 3308, 3488, 259, 72, 2418, 2630, 3478,
+ 3707, 1736, 1926, 305, 2759, 1670, 2385, 3250, 2974, 3094, 2653, 1620, 1873, 1678,
+ 2093, 3164, 2832, 2034, 1924, 3593, 1840, 558, 2318, 2625, 1398, 3095, 1939, 3741,
+ 1890, 2959, 3508, 3394, 2992, 3651, 2954, 3728, 3492, 1744, 3476, 3570, 1030, 2148,
+ 3351, 2202, 2292, 12, 129, 3629, 3613, 1707, 3754, 3098, 3769, 3672, 3763, 781,
+ 1649, 416, 1027, 706, 2595, 3773, 1971, 1696, 3278, 3490, 3783, 3766, 3698, 3179,
+ 1650, 2181, 2424, 260, 3755, 2190, 1406, 3177, 3105, 2323, 3124, 2046, 3209, 3571,
+ 3702, 1657, 3011, 1578, 3252, 3456, 3194, 1251, 1973, 636, 1139, 1412, 3483, 336,
+ 3623, 3764, 1665, 3814, 3610, 631, 186, 2617, 2523, 2590, 3587, 3724, 2904, 3802,
+ 3627, 2680, 3562, 3403, 138, 1720, 1655, 3342, 1439, 989, 3376, 3836, 3839, 3544,
+ 2461, 3800, 3711, 3456, 1270, 966, 3726, 3659, 3773, 3852, 3515, 3755, 293, 2235,
+ 1752, 458, 3666, 2797, 3005, 2463, 3093, 3161, 2767, 3477, 3162, 3406, 3485, 2151,
+ 2023, 3032, 1855, 3464, 2437, 2708, 3813, 1847, 3339, 1085, 36, 3159, 1401, 736,
+ 3872, 1044, 3150, 3745, 3603, 1918, 2150, 3888, 2250, 2914, 1597, 33, 3725, 3676,
+ 3837, 3758, 3834, 513, 3262, 1524, 3884, 3289, 3876, 3877, 18, 56, 3293, 1101,
+ 1249, 3090, 3837, 1468, 3652, 120, 3537, 2991, 1170, 883, 538, 3885, 2368, 2954,
+ 810, 3369, 3221, 1751, 3914, 3049, 1760, 3919, 3190, 3868, 3935, 3767, 2025, 3902,
+ 3131, 3857, 3902, 567, 690, 2499, 637, 1555, 230, 3335, 1355, 3937, 1240, 2733,
+ 1503, 1042, 1877, 2097, 3959, 1686, 3863, 3838, 854, 1131, 371, 3635, 1791, 709,
+ 1472, 2959, 2226, 482, 1152, 1024, 3169, 3677, 3788, 1907, 3059, 1606, 3809, 2782,
+ 3983, 2563, 3578, 222, 3363, 1830, 861, 1397, 3990, 720, 2864, 3973, 3848, 620,
+ 884, 3872, 3999, 2968, 3515, 3894, 3887, 3883, 2778, 1957, 2448, 2833, 3832, 3884,
+ 3951, 1638, 176, 3370, 3871, 3812, 516, 2483, 133, 384, 3978, 1783, 2078, 3731,
+ 3199, 4026, 3973, 2744, 4018, 2598, 3490, 2800, 3695, 3891, 57, 2391, 3983, 812,
+ 3863, 4031, 2483, 1602, 3667, 3503, 1166, 2270, 3603, 3459, 3921, 4049, 2050, 368,
+ 28, 4008, 1554, 3169, 3978, 3996, 2652, 2447, 4042, 764, 1182, 732, 3878, 4026,
+ 1383, 3860, 4061, 1363, 3942, 2083, 2428, 934, 3865, 3540, 3307, 2368, 2666, 3483,
+ 4010, 2728, 1454, 2225, 3648, 3476, 3811, 3592, 3339, 3548, 3973, 3979, 4061,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 2;
+ let segment_n = 0;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 3058, 3853, 3996, 3939, 1160, 3958, 2783, 2771, 3906, 3745, 2022, 3383, 2446, 4078,
+ 2898, 4091, 2517, 1562, 1308, 3, 4075, 3762, 3623, 1619, 4055, 4090, 4071, 2811,
+ 2414, 3947, 3842, 26, 3829, 3742, 2823, 2080, 2772, 2814, 36, 3879, 38, 3755, 3824,
+ 3921, 3814, 4049, 1744, 2237, 44, 47, 3914, 4071, 3283, 41, 3991, 9, 1207, 2279,
+ 2572, 1204, 3898, 42, 1276, 4002, 3593, 3311, 1593, 12, 3465, 30, 1965, 27, 3744,
+ 1184, 1793, 1827, 3963, 1574, 2898, 2945, 75, 2729, 3982, 3178, 46, 3227, 67, 1565,
+ 3377, 1784, 2444, 2511, 3723, 3486, 3934, 4087, 2188, 3037, 3263, 2394, 2859, 2784,
+ 3427, 11, 4057, 3699, 2739, 3690, 10, 1193, 85, 3513, 3712, 3198, 3759, 36, 3752,
+ 4076, 2378, 22, 101, 1829, 48, 3728, 1, 2863, 55, 1750, 4017, 3894, 55, 1958, 2442,
+ 3950, 4024, 1767, 4082, 74, 3754, 1149, 138, 1982, 4076, 1571, 3017, 143, 3387,
+ 2051, 2260, 1249, 3789, 1259, 2502, 1948, 100, 3732, 3070, 155, 2362, 4, 157, 2516,
+ 1208, 2827, 3377, 15, 147, 1296, 2341, 3295, 1810, 167, 3910, 141, 4062, 3032,
+ 3592, 163, 1808, 141, 3443, 97, 3562, 58, 1525, 1235, 3953, 17, 1783, 3650, 3495,
+ 147, 1407, 151, 3702, 182, 3493, 3562, 80, 1394, 2525, 4020, 2600, 3701, 140, 2550,
+ 3581, 1661, 1216, 2051, 2569, 2315, 132, 3036, 3927, 148, 3011, 1180, 98, 211,
+ 1561, 3798, 3754, 3622, 1663, 179, 1493, 3975, 3365, 3797, 4039, 2775, 222, 3191,
+ 1207, 1989, 2631, 3464, 191, 155, 1299, 3724, 3415, 3052, 2193, 3950, 1239, 3797,
+ 3613, 2637, 1454, 149, 3735, 1994, 2608, 3662, 157, 51, 2561, 3755, 3913, 2933,
+ 4042, 4067, 2901, 3462, 3961, 2567, 2862, 169, 121, 4, 3912, 1349, 4051, 1699, 273,
+ 1727, 276, 1867, 3118, 2998, 172, 1680, 2118, 25, 1980, 3089, 2164, 3828, 226, 273,
+ 3623, 4019, 2632, 280, 2009, 141, 2790, 2501, 1636, 4062, 299, 301, 3874, 3785,
+ 2463, 1664, 3601, 2163, 128, 177, 3014, 1738, 4031, 2055, 3119, 220, 283, 3179,
+ 3725, 3460, 2479, 4055, 1767, 2109, 3384, 3505, 4016, 3655, 2880, 3629, 3110, 1403,
+ 1393, 1523, 1533, 3925, 2515, 281, 1705, 221, 3406, 167, 3397, 1082, 326, 248,
+ 4061, 3268, 348, 1919, 1040, 291, 3994, 1733, 159, 281, 3482, 3840, 3908, 322, 242,
+ 2896, 323, 2115, 3049, 2547, 159, 355, 1522, 2090, 3999, 3526, 269, 3234, 3864,
+ 2647, 4055, 353, 1348, 3530, 359, 3262, 162, 3802, 381, 3706, 289, 3107, 3746,
+ 3662, 3109, 371, 2049, 3413, 3415, 2118, 2636, 163, 2396, 3566, 343, 396, 1447,
+ 2139, 404, 1552, 2442, 1648, 1522, 259, 218, 385, 3020, 1915, 406, 2360, 1970,
+ 2470, 3671, 2444, 2730, 3714, 2803, 1732, 3859, 227, 4017, 420, 2443, 200, 1966,
+ 296, 2940, 416, 243, 138, 418, 99, 406, 148, 3108, 3354, 3598, 368, 2626, 330,
+ 1780, 2970, 2752, 2354, 2360, 2648, 422, 1870, 3581, 446, 1355, 2820, 1972, 277,
+ 1396, 3807, 3626, 323, 196, 1903, 2051, 3693, 3041, 343, 2071, 3462, 1052, 2422,
+ 471, 2634, 1060, 1801, 3204, 3006, 1722, 1618, 1294, 1729, 304, 1881, 3998, 2183,
+ 2038, 3005, 218, 99, 491, 3470, 1964, 420, 2160, 2000, 2562, 1849, 91, 148, 242,
+ 3840, 2665, 2523, 253, 37, 1503, 2947, 3106, 507, 1399, 1546, 3281, 1906, 241,
+ 1254, 166, 330, 3267, 2960, 3322, 3658, 4014, 3336, 449, 3025, 225, 2588, 3133,
+ 140, 2394, 2280, 30, 196, 2418, 3234, 3362, 371, 2280, 317, 2089, 2096, 3265, 135,
+ 2328, 1093, 1863, 3852, 3920, 3155, 462, 1941, 3730, 514, 1965, 425, 2262, 3648,
+ 377, 2598, 2204, 281, 467, 326, 3136, 3698, 2074, 2290, 417, 1445, 3815, 392, 531,
+ 2503, 3932, 360, 494, 3464, 1906, 3779, 2719, 1366, 255, 577, 2807, 3710, 1962,
+ 2136, 310, 333, 3721, 2256, 1954, 2880, 43, 467, 1394, 2442, 207, 3683, 372, 596,
+ 1258, 3204, 2256, 3816, 608, 528, 2415, 3834, 235, 3352, 2616, 3447, 3751, 3372,
+ 3086, 284, 573, 3016, 533, 1150, 9, 3793, 2824, 554, 1599, 2002, 588, 3541, 513,
+ 612, 601, 424, 4094, 3084, 34, 3438, 1802, 1325, 641, 2232, 3743, 279, 346, 570,
+ 1494, 1140, 291, 4041, 646, 3652, 157, 566, 2510, 2160, 3838, 1545, 1048, 566,
+ 3305, 584, 2678, 634, 179, 1724, 2191, 669, 3655, 595, 3555, 402, 129, 1663, 2849,
+ 2758, 2725, 565, 3331, 681, 279, 2112, 505, 3634, 1954, 3995, 3253, 3566, 361, 688,
+ 192, 570, 3814, 2131, 1564, 2718, 308, 2879, 1247, 1933, 648, 2675, 1107, 2115,
+ 2766, 2083, 1666, 2952, 710, 3295, 1642, 1752, 498, 130, 3500, 2187, 717, 64, 3504,
+ 2226, 4026, 719, 3656, 603, 176, 3668, 2410, 1248, 2643, 1850, 196, 2817, 728, 612,
+ 3225, 245, 648, 238, 726, 3525, 2901, 1525, 230, 540, 3479, 735, 3108, 459, 377,
+ 735, 1396, 3137, 3899, 669, 2199, 3822, 527, 3470, 54, 754, 3000, 2673, 2338, 600,
+ 3911, 1807, 4079, 3644, 413, 4078, 609, 592, 748, 2437, 1585, 2297, 334, 1828, 33,
+ 1760, 3046, 760, 2789, 476, 779, 353, 1736, 3326, 625, 1826, 637, 747, 568, 640,
+ 2909, 512, 4062, 492, 3001, 765, 194, 1369, 637, 196, 806, 3050, 586, 2583, 728,
+ 2073, 533, 796, 812, 2494, 3823, 729, 55, 516, 3129, 2735, 793, 6, 719, 554, 768,
+ 690, 3235, 818, 2714, 2818, 4050, 829, 2117, 1983, 3143, 2707, 587, 783, 1684, 460,
+ 2502, 278, 828, 3609, 568, 1822, 1584, 211, 604, 3429, 624, 212, 3131, 3708, 2853,
+ 1662, 124, 455, 1054, 433, 1751, 3257, 283, 308, 456, 1745, 1341, 183, 1182, 655,
+ 687, 4047, 508, 3890, 3948, 1273, 498, 1037, 774, 821, 537, 373, 586, 1924, 638,
+ 2047, 2263, 1582, 2722, 824, 856, 3894, 739, 477, 409, 567, 3199, 852, 359, 2558,
+ 445, 2936, 3781, 2128, 617, 558, 1694, 3969, 4013, 3970, 2373, 3606, 426, 3545,
+ 1838, 1454, 1956, 915, 1227, 3411, 863, 339, 1703, 874, 1506, 2982, 77, 3407, 4015,
+ 697, 192, 4054, 3737, 3634, 186, 747, 1230, 20, 938, 1206, 801, 3529, 375, 487,
+ 2595, 925, 2865, 1230, 2263, 948, 3773, 87, 2227, 1037, 2741, 3943, 3986, 265, 905,
+ 3295, 917, 497, 292, 3292, 1688, 749, 3908, 66, 2665, 469, 1291, 3939, 1166, 436,
+ 2058, 2046, 930, 3745, 3928, 929, 707, 3462, 3951, 3657, 308, 164, 4046, 3826,
+ 2108, 2555, 3633, 721, 208, 2778, 3144, 1349, 957, 2632, 256, 992, 3949, 3977, 772,
+ 1484, 731, 1500, 346, 1490, 353, 3955, 2943, 362, 1964, 468, 81, 549, 59, 377, 351,
+ 402,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 2;
+ let segment_n = 1;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 245, 305, 3307, 2804, 3940, 209, 4024, 3645, 611, 3393, 168, 3928, 855, 917, 956,
+ 2253, 2645, 956, 3289, 927, 259, 2123, 3793, 470, 886, 392, 1024, 4063, 697, 1047,
+ 2858, 315, 2069, 2236, 2652, 871, 682, 996, 2717, 4003, 888, 2851, 948, 563, 3795,
+ 749, 846, 3966, 3264, 980, 427, 2546, 527, 108, 243, 666, 2669, 3825, 3882, 374,
+ 1056, 2290, 1077, 162, 3737, 3960, 3477, 316, 1042, 3933, 3274, 4014, 1079, 1092,
+ 3586, 4061, 566, 4000, 4061, 2186, 3418, 3459, 463, 3180, 3358, 785, 439, 3488,
+ 910, 1093, 2716, 3731, 1061, 939, 3079, 1097, 2319, 613, 3867, 448, 1074, 176, 528,
+ 2936, 516, 3759, 463, 99, 3882, 22, 1031, 549, 1047, 623, 710, 1093, 2886, 584,
+ 1140, 3834, 3626, 1101, 2137, 2626, 590, 846, 3532, 1149, 1119, 1115, 3105, 1130,
+ 246, 3008, 17, 2494, 705, 199, 2383, 1105, 18, 2638, 1124, 1075, 3896, 1083, 1102,
+ 4040, 788, 3048, 1157, 3309, 515, 3434, 798, 83, 3501, 1179, 304, 2806, 888, 1107,
+ 2551, 754, 3122, 2054, 877, 3501, 1185, 3636, 1192, 3037, 623, 286, 575, 2929, 420,
+ 1196, 2193, 980, 1105, 2523, 432, 3219, 869, 4049, 240, 1055, 1133, 1192, 739, 863,
+ 2193, 2298, 925, 2196, 1148, 1030, 732, 870, 1084, 2500, 349, 1225, 1121, 4017,
+ 4054, 611, 623, 1022, 1195, 562, 3575, 1233, 2288, 2974, 1020, 3573, 461, 589, 417,
+ 47, 303, 1074, 648, 1231, 1248, 3161, 838, 688, 2296, 3065, 126, 691, 980, 2487,
+ 1129, 229, 3139, 151, 1136, 427, 47, 2320, 958, 239, 1268, 47, 308, 751, 1150,
+ 2048, 1263, 3980, 998, 1189, 2903, 3569, 1086, 1016, 3418, 2253, 3556, 4005, 1180,
+ 1207, 965, 923, 86, 3912, 1241, 443, 3707, 2237, 644, 1065, 3369, 2427, 1132, 44,
+ 1237, 3181, 1249, 1276, 1097, 1260, 174, 1300, 3652, 1297, 3291, 654, 1289, 960,
+ 830, 994, 2510, 1318, 499, 3525, 1265, 1141, 3494, 897, 1288, 33, 2643, 10, 2199,
+ 3067, 3918, 972, 1232, 645, 430, 516, 2337, 2623, 1039, 25, 725, 777, 3300, 1123,
+ 2342, 4025, 993, 324, 3892, 1338, 1027, 1238, 4002, 968, 1331, 37, 3431, 2581,
+ 3063, 3096, 1328, 2057, 1009, 563, 769, 362, 3542, 475, 965, 873, 2513, 2631, 1359,
+ 314, 1285, 1294, 235, 1119, 3155, 2273, 2207, 1018, 22, 590, 2601, 1139, 3405,
+ 1382, 168, 3976, 2053, 2563, 1034, 2179, 1325, 828, 1396, 1301, 694, 738, 890, 898,
+ 1389, 408, 3932, 1363, 176, 2630, 445, 3327, 3657, 1412, 3156, 831, 443, 2650, 606,
+ 78, 2486, 1308, 517, 974, 2541, 443, 1359, 2459, 490, 962, 4073, 950, 827, 1248,
+ 700, 815, 3514, 1409, 1417, 1381, 2050, 2938, 1350, 332, 3609, 2575, 1441, 4055,
+ 634, 2524, 4074, 1358, 1444, 1432, 1077, 590, 1424, 2313, 897, 886, 1166, 1364,
+ 3767, 2997, 898, 1431, 539, 1141, 3348, 2795, 868, 1232, 1269, 909, 1347, 3624,
+ 3245, 1044, 334, 179, 892, 109, 1470, 773, 765, 291, 2756, 2283, 913, 846, 2810,
+ 871, 2756, 1234, 1245, 179, 204, 2128, 1160, 3116, 1477, 2512, 390, 767, 1074,
+ 2523, 262, 1502, 1312, 2838, 2184, 768, 1487, 1405, 991, 1096, 2645, 2984, 3528,
+ 769, 3452, 2780, 1450, 3164, 1433, 4, 490, 383, 2964, 2970, 3040, 1405, 38, 552,
+ 1534, 758, 3430, 329, 1497, 1232, 3708, 1128, 1083, 3133, 1467, 1545, 1466, 508,
+ 2348, 870, 1004, 1476, 1552, 534, 3803, 1405, 3588, 3265, 3260, 674, 1439, 711,
+ 1137, 970, 1045, 1539, 545, 1550, 1568, 1177, 3757, 125, 1567, 895, 377, 28, 2674,
+ 2505, 748, 2593, 3465, 1029, 1183, 804, 3142, 1053, 1544, 1116, 494, 2078, 1120,
+ 1549, 2581, 2397, 3376, 2176, 636, 1093, 2823, 1503, 937, 3053, 571, 1581, 299,
+ 1333, 1486, 1598, 1606, 3975, 911, 1583, 1587, 3454, 1152, 1558, 970, 1550, 3723,
+ 2663, 1476, 1128, 1489, 1589, 1433, 3506, 2497, 1552, 1287, 1387, 55, 1434, 4005,
+ 3971, 3550, 1611, 459, 995, 3143, 1637, 1619, 1390, 513, 1411, 502, 3425, 1597,
+ 1535, 2383, 109, 1436, 3216, 1346, 1421, 3212, 1601, 616, 1443, 1648, 2301, 1645,
+ 1328, 1650, 82, 226, 307, 1666, 861, 414, 3262, 1014, 1003, 1473, 4035, 4079, 984,
+ 374, 3761, 4021, 1150, 2932, 1196, 1455, 1681, 1625, 1132, 405, 1273, 1552, 2947,
+ 3987, 2071, 3912, 3980, 1694, 1589, 1112, 55, 1493, 1461, 1465, 1557, 934, 1687,
+ 1044, 1317, 3014, 1466, 3961, 3956, 3299, 214, 2427, 3963, 3145, 676, 491, 3522,
+ 2841, 1588, 1706, 1694, 35, 1719, 1188, 1707, 1304, 3273, 1564, 1690, 2256, 1471,
+ 100, 607, 940, 2693, 1334, 1640, 852, 1738, 588, 1733, 3203, 1517, 1677, 2448,
+ 1742, 3501, 1714, 444, 1673, 1416, 4011, 2284, 1753, 3912, 1231, 2921, 2947, 861,
+ 3720, 1496, 1263, 1384, 2112, 1281, 1480, 3686, 3955, 3989, 1290, 3489, 1124, 1770,
+ 2283, 618, 2836, 1413, 1503, 2257, 802, 1026, 2386, 516, 1412, 2787, 502, 1167,
+ 3816, 1701, 1603, 2125, 316, 3629, 1473, 1426, 1452, 1478, 1747, 3456, 1184, 2563,
+ 1681, 3136, 1617, 1406, 3562, 866, 153, 1621, 21, 1660, 1765, 1054, 1642, 335,
+ 1792, 730, 3773, 2429, 1732, 1378, 1746, 947, 1431, 3103, 945, 1698, 1488, 3433, 4,
+ 1831, 736, 469, 3095, 303, 376, 2759, 2259, 202, 854, 1348, 2437, 2954, 1828, 1206,
+ 1344, 1837, 3780, 1794, 747, 3928, 1817, 929, 1662, 1772, 1199, 3262, 1297, 1191,
+ 1773, 2908, 1122, 1860, 1214, 2310, 2918, 1829, 3371, 24, 1868, 1777, 536, 732,
+ 2223, 3738, 783, 1594, 1555, 703, 1131, 1257, 2780, 1666, 1671, 2690, 1181, 1769,
+ 23, 1016, 1551, 3351, 1660, 1493, 106, 765, 1598, 1043, 1699, 1889, 1057, 1901,
+ 2070, 3725, 857, 739, 2359, 49, 1486, 293, 3395, 3384, 2468, 1867, 1631, 3838,
+ 1432, 1450, 822, 2971, 1303, 1847, 3460, 1621, 772, 1924, 1287, 1926, 1654, 303,
+ 2395, 3994, 172, 3677, 1920, 1755, 2844, 1651, 1922, 1513, 4058, 854, 3068, 2, 741,
+ 1739, 1296, 1794, 3229, 1872, 1924, 2254, 730, 1023, 3703, 1349, 1692, 1406, 3815,
+ 1492, 40, 3040, 334, 1727, 591, 1503, 1733, 2691, 3063, 1204, 2722, 1665, 3895,
+ 1924, 3565, 3795, 1905, 3843, 3897, 1817, 1888, 1538, 224, 1476, 2081, 1280, 3972,
+ 2200, 1105, 3469, 3685, 1909, 974, 2516, 382, 1389, 2366, 2750, 136, 2174, 1915,
+ 1622, 2519, 3999, 3674, 1649, 1706, 757, 3776, 2898, 1614, 158, 450, 15, 2013,
+ 1852, 1930, 438, 1851, 775, 1746, 1870, 1021, 997, 1742, 1756, 2767, 1982, 1882,
+ 72, 1961, 2296, 2940, 2570, 2569, 2878, 3652, 3774, 2212, 2599, 30, 2183, 248, 508,
+ 1543, 2967,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 2;
+ let segment_n = 2;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 2035, 1527, 238, 1387, 1882, 1932, 772, 2047, 1735, 918, 619, 450, 1107, 783, 1692,
+ 181, 1995, 1895, 1973, 2045, 630, 1584, 1150, 3855, 2055, 2068, 3155, 1949, 3884,
+ 2064, 1369, 3749, 1961, 1505, 2058, 3972, 1019, 3196, 1559, 334, 1041, 3306, 2080,
+ 3189, 1988, 770, 805, 3651, 990, 486, 981, 237, 1270, 4085, 161, 18, 1821, 1330,
+ 1615, 3327, 2074, 487, 1759, 1580, 241, 4002, 1819, 1152, 2113, 3801, 1057, 1844,
+ 3249, 214, 719, 3415, 1180, 1917, 1546, 2085, 65, 1568, 2108, 960, 1645, 1794,
+ 2095, 686, 1295, 1334, 1685, 1041, 1959, 594, 1253, 1184, 1896, 529, 960, 2037,
+ 1027, 1117, 2085, 4042, 353, 3849, 3936, 69, 1912, 2006, 3887, 502, 655, 2139, 330,
+ 1314, 3872, 3847, 937, 390, 1126, 2129, 252, 2078, 1960, 2134, 891, 329, 1555,
+ 3363, 1063, 119, 1836, 978, 1896, 2072, 1517, 1828, 3173, 2159, 1246, 987, 1801,
+ 1742, 1975, 1655, 539, 1680, 457, 541, 2159, 1433, 447, 484, 8, 3129, 221, 2050,
+ 2185, 1393, 3686, 1950, 1543, 2121, 1955, 46, 2102, 1364, 2179, 2208, 2207, 2201,
+ 1802, 2142, 3986, 1943, 1240, 2197, 1812, 1624, 1790, 2023, 3355, 856, 1343, 1692,
+ 2079, 941, 3515, 2049, 2223, 1295, 1925, 2203, 3630, 696, 1966, 1206, 598, 3214,
+ 1658, 723, 2223, 1747, 236, 3337, 1868, 1392, 1965, 2110, 1514, 495, 1677, 2082,
+ 4052, 1710, 2110, 1918, 1324, 209, 3166, 1858, 1639, 1968, 1222, 1703, 1312, 2086,
+ 3249, 1263, 585, 245, 1354, 1907, 1829, 1338, 2280, 2189, 2246, 2170, 4095, 2103,
+ 2016, 612, 1554, 408, 1300, 1448, 4004, 2247, 2196, 1611, 248, 2242, 1056, 435,
+ 1470, 3828, 3731, 2302, 1054, 620, 3198, 1184, 2231, 3501, 1603, 2298, 73, 1048,
+ 2033, 1083, 1408, 1217, 274, 685, 3146, 2276, 2318, 2267, 1215, 2226, 2318, 3464,
+ 2328, 83, 2117, 2084, 2224, 3485, 209, 1872, 3575, 1809, 360, 1550, 3677, 3607,
+ 4004, 2343, 2043, 2341, 1501, 1661, 2218, 3854, 3250, 2098, 2036, 2355, 61, 419,
+ 2313, 1461, 2009, 2045, 2362, 344, 1799, 1832, 1092, 3573, 984, 3644, 1308, 2253,
+ 3240, 2332, 1096, 1225, 1769, 2226, 2284, 1260, 2214, 1693, 1240, 1936, 1619, 2240,
+ 2198, 2371, 3453, 3394, 1961, 2140, 304, 728, 1263, 2390, 1404, 2280, 2397, 3945,
+ 2101, 2381, 309, 435, 2160, 505, 1047, 1230, 1615, 2326, 2268, 2403, 1512, 3918,
+ 778, 3112, 1563, 2126, 88, 1048, 2418, 1924, 2419, 3248, 2377, 2307, 2098, 2062,
+ 1810, 1076, 2404, 2179, 2243, 1305, 2400, 1665, 1967, 2268, 4034, 3705, 2234, 1704,
+ 1814, 2414, 879, 1628, 902, 835, 337, 1010, 2332, 1992, 1013, 2407, 639, 454, 2333,
+ 1974, 720, 2448, 894, 1865, 3662, 1562, 611, 318, 1662, 670, 2364, 1748, 2280,
+ 1884, 1018, 2170, 2428, 881, 422, 2403, 2181, 2003, 3416, 3384, 2156, 3463, 3256,
+ 951, 1222, 1660, 1499, 1802, 644, 1432, 1886, 1431, 2398, 1953, 1760, 601, 469,
+ 2429, 1034, 3421, 1881, 1723, 1311, 509, 1924, 147, 2266, 1958, 2473, 3313, 1730,
+ 2371, 1176, 2475, 1968, 4088, 1736, 2057, 2143, 3518, 1874, 2011, 1144, 912, 2251,
+ 1926, 3997, 232, 50, 1051, 98, 2315, 2366, 1077, 894, 3202, 1669, 547, 3956, 1429,
+ 2193, 1156, 330, 1568, 143, 1071, 933, 1409, 2245, 2493, 153, 3256, 3702, 2374,
+ 2544, 3867, 2362, 1948, 1353, 2404, 1787, 1249, 2101, 555, 3478, 572, 2413, 838,
+ 2510, 690, 2018, 1479, 748, 2513, 2506, 808, 2557, 1671, 2504, 2581, 2077, 1660,
+ 826, 636, 2531, 3192, 3694, 18, 1865, 2295, 2523, 1469, 3764, 2454, 2020, 3543,
+ 2202, 1490, 2596, 2474, 3426, 2381, 474, 2384, 1500, 2137, 2467, 2545, 2496, 1799,
+ 2462, 2319, 2497, 3108, 1526, 1792, 1522, 2558, 2217, 2621, 3115, 2406, 1886, 2361,
+ 1047, 117, 331, 2257, 1277, 628, 2460, 2515, 2399, 1183, 2489, 769, 3784, 2633,
+ 3490, 1349, 1715, 2043, 1635, 2217, 3882, 2617, 2172, 2278, 1986, 2399, 2545, 2114,
+ 2205, 1769, 2618, 916, 3855, 85, 4010, 2365, 688, 882, 2401, 1883, 2401, 1728,
+ 2630, 1495, 3974, 1969, 2163, 2672, 2407, 2293, 2398, 3379, 1552, 3484, 2286, 2467,
+ 127, 614, 1644, 1243, 2570, 1436, 949, 1805, 1497, 1025, 3865, 1522, 3241, 2611,
+ 2178, 2684, 330, 1889, 3549, 535, 2252, 3890, 2408, 1604, 2337, 450, 4062, 1590,
+ 2709, 2206, 2313, 270, 1379, 1281, 719, 2622, 2457, 2482, 3595, 1234, 1854, 2718,
+ 2147, 2719, 2164, 1910, 289, 2516, 3366, 1953, 1347, 1671, 2059, 2650, 2686, 1720,
+ 2714, 2138, 2636, 1658, 1030, 1365, 634, 1873, 993, 2541, 543, 2707, 590, 2636,
+ 647, 3604, 3337, 3418, 3921, 2480, 3347, 2422, 1033, 3756, 2354, 2732, 1562, 2687,
+ 3757, 3553, 1962, 2069, 2696, 1944, 94, 54, 2710, 1133, 2341, 1271, 88, 3516, 734,
+ 3683, 1328, 3323, 2770, 2785, 1317, 2352, 2738, 1973, 2065, 2160, 2685, 2275, 3378,
+ 902, 3209, 441, 2228, 1205, 368, 2566, 2136, 2800, 2804, 2551, 2196, 2354, 2559,
+ 2655, 2659, 1754, 1629, 1334, 2743, 2778, 1044, 766, 3295, 1868, 3241, 116, 2818,
+ 2670, 3890, 332, 2734, 1835, 406, 683, 2625, 2383, 2251, 3388, 3615, 2659, 680,
+ 3667, 1525, 567, 1707, 2400, 2095, 2261, 2368, 2584, 2111, 2580, 1070, 1023, 2796,
+ 2492, 1196, 1106, 615, 1094, 2030, 2219, 2254, 2830, 1822, 2229, 2851, 1889, 2753,
+ 1157, 2388, 1418, 367, 2816, 1513, 2865, 763, 2161, 2793, 2680, 2634, 2598, 2188,
+ 3423, 2871, 2839, 2427, 933, 710, 1300, 2825, 2536, 2578, 789, 1387, 2245, 2708,
+ 2543, 49, 2702, 1166, 862, 2898, 2203, 1409, 3405, 2297, 2572, 375, 2755, 3209,
+ 489, 2904, 2865, 2545, 3812, 822, 473, 3135, 2915, 342, 3509, 2847, 2793, 1574,
+ 2456, 2517, 1100, 1330, 892, 2836, 3089, 3665, 1413, 2887, 1303, 218, 3378, 1333,
+ 1253, 2290, 2727, 132, 2805, 2424, 912, 551, 298, 1178, 2084, 2862, 3739, 2637,
+ 1538, 2780, 818, 2950, 2909, 367, 759, 2510, 1192, 4048, 152, 964, 2960, 1699,
+ 2898, 2865, 2283, 2568, 1537, 3974, 3300, 2138, 2083, 890, 2798, 1547, 65, 2815,
+ 2105, 920, 245, 1841, 2298, 1993, 2117, 2088, 2691, 1495, 940, 2704, 338, 3322,
+ 3797, 562, 97, 885, 2154, 1804, 209, 2267, 1714, 2252, 977, 3183, 2821, 2269, 2493,
+ 2440, 1060, 2817, 323, 1022, 1216, 2998, 2843, 3595, 3945, 1765, 2894, 3175, 1471,
+ 3668, 1426, 2172, 1766, 2821, 1321, 1238, 2172, 2586, 82, 2691, 2744, 1962, 670,
+ 1797, 1041, 2964, 3210, 4078, 2710, 2481, 710, 1630, 3461, 560, 106, 2097, 2669,
+ 2057, 2404, 2172, 2158, 3484, 3043, 3983, 3055, 3944, 3050, 3979, 3551, 1834, 2393,
+ 3171, 349, 1296, 1876, 2988, 1789, 3580, 1396,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+
+ let offset = 0;
+ let pass_n = 2;
+ let segment_n = 3;
+
+ gidx.init(pass_n, segment_n, offset, &mut tmp_block);
+
+ let expected_ref_idx: [u32; 1024] = [
+ 1775, 3037, 2997, 1590, 386, 2714, 2140, 2437, 2432, 3079, 3079, 3044, 2964, 1089,
+ 398, 1962, 147, 2898, 764, 2571, 3066, 2723, 2452, 3078, 1811, 3091, 2278, 2171,
+ 2975, 2769, 3075, 3059, 2287, 2984, 1204, 1290, 1391, 2408, 1067, 2605, 2863, 1713,
+ 2479, 2690, 2005, 2619, 3116, 2718, 2142, 2468, 3112, 2400, 2547, 3093, 159, 1185,
+ 3126, 3080, 1683, 853, 838, 3044, 3101, 2693, 190, 2946, 1083, 1338, 470, 2521,
+ 2953, 2942, 2715, 3061, 3134, 3144, 832, 2058, 2223, 2002, 2015, 1887, 1236, 1367,
+ 3094, 3155, 419, 3084, 2718, 1890, 3158, 1458, 2741, 515, 1658, 1262, 1105, 2431,
+ 3166, 938, 800, 3160, 489, 3005, 3155, 2399, 3110, 1567, 3028, 2841, 3129, 841,
+ 3110, 3154, 3183, 2132, 37, 3127, 2310, 746, 3111, 1939, 1903, 1636, 3153, 1758,
+ 929, 2829, 988, 1130, 3148, 2130, 439, 1507, 1142, 1977, 784, 1131, 1494, 2481,
+ 1606, 1878, 2940, 955, 3087, 957, 1532, 2962, 397, 3204, 3158, 2651, 3204, 3192,
+ 157, 1903, 1050, 2595, 2738, 3129, 3229, 1987, 547, 2474, 3092, 3125, 3165, 3075,
+ 945, 2061, 2555, 1040, 2797, 823, 406, 3173, 3246, 3208, 2812, 2411, 1723, 1508,
+ 3145, 2944, 1977, 3208, 1036, 2971, 3093, 923, 2206, 204, 3257, 1160, 1484, 1694,
+ 3249, 1132, 1774, 2050, 2430, 1477, 2204, 1408, 2149, 3186, 3217, 3160, 660, 1875,
+ 1157, 617, 2748, 1973, 1881, 753, 314, 3030, 1987, 2162, 2711, 876, 3021, 2418,
+ 2394, 1813, 569, 2873, 210, 2765, 3287, 2916, 120, 3123, 3303, 2921, 1881, 751,
+ 1292, 1914, 3307, 1939, 2144, 1985, 3250, 645, 1324, 1965, 1193, 1043, 1264, 3143,
+ 310, 3247, 3085, 2670, 140, 1466, 3125, 2527, 3227, 2486, 1920, 3230, 3334, 1211,
+ 3241, 2593, 1396, 3339, 3116, 3164, 197, 2695, 1489, 1769, 1342, 1941, 2711, 311,
+ 3127, 2464, 921, 2398, 3218, 2936, 2620, 533, 2460, 1775, 1306, 1965, 3168, 1882,
+ 3292, 3303, 3219, 3251, 2616, 1435, 2191, 2254, 387, 3254, 2921, 3308, 2759, 851,
+ 1799, 3367, 3224, 1728, 2347, 1832, 3016, 3350, 2206, 3340, 1146, 3389, 3256, 1231,
+ 1966, 3122, 2962, 3087, 3375, 2410, 3117, 2759, 3073, 3304, 3402, 3159, 3369, 3403,
+ 1138, 1542, 2281, 3297, 2358, 724, 3072, 2656, 1737, 1099, 3326, 1334, 3366, 202,
+ 2835, 1833, 498, 3141, 226, 3077, 3125, 3364, 3287, 3214, 1519, 1703, 1715, 2652,
+ 1504, 3339, 2566, 3259, 1462, 2979, 3349, 1955, 1343, 3431, 1414, 3143, 3279, 583,
+ 1337, 2458, 3210, 1467, 3450, 1628, 3030, 2147, 1686, 3391, 1352, 1815, 792, 1189,
+ 3168, 3041, 3028, 202, 2700, 3414, 2447, 3422, 1267, 3200, 785, 3402, 1081, 3339,
+ 553, 2950, 2959, 2628, 2252, 2829, 3068, 2489, 3151, 2854, 3271, 1167, 536, 3355,
+ 3483, 2289, 3167, 2527, 1175, 2643, 3452, 3369, 1212, 163, 3134, 2528, 2769, 3481,
+ 2495, 138, 28, 3012, 2431, 610, 2772, 1706, 3507, 1733, 2968, 3495, 3309, 1860,
+ 225, 1301, 814, 1040, 3408, 253, 69, 3364, 2958, 666, 3395, 2936, 499, 3531, 2939,
+ 811, 3080, 3535, 2026, 3270, 127, 924, 3427, 1110, 3517, 3323, 3510, 1569, 3173,
+ 3542, 1016, 432, 3153, 2738, 798, 2811, 1199, 146, 234, 1277, 3397, 592, 3035,
+ 3043, 2841, 860, 2509, 2832, 3517, 3516, 2302, 3325, 1223, 3141, 3394, 1958, 257,
+ 2196, 958, 2652, 3416, 3265, 3446, 3546, 3335, 2798, 570, 3240, 2617, 1031, 3578,
+ 1768, 2767, 3587, 3588, 592, 865, 3530, 2813, 1742, 3177, 1400, 1233, 3236, 3368,
+ 702, 1087, 2580, 2976, 2733, 109, 3378, 3432, 2733, 3578, 3457, 537, 2644, 3587,
+ 1484, 3610, 3589, 3570, 1212, 2479, 1890, 2806, 490, 3274, 2528, 3628, 2317, 3618,
+ 3140, 2599, 3514, 3614, 3152, 353, 3186, 335, 3338, 3436, 3640, 174, 2053, 2313,
+ 149, 3561, 3637, 2245, 2978, 978, 3267, 818, 2328, 2442, 3164, 2826, 958, 3108,
+ 3639, 1313, 2787, 2502, 785, 3563, 3337, 1928, 3039, 3275, 3175, 654, 3641, 1238,
+ 3267, 961, 3344, 3610, 2188, 3568, 3645, 3650, 2739, 2453, 3329, 2250, 3366, 1835,
+ 877, 2135, 2479, 3425, 1106, 3458, 1106, 2769, 711, 2068, 3665, 560, 2255, 237,
+ 3356, 1259, 2466, 1327, 1673, 3654, 3275, 1711, 2422, 2215, 1551, 2230, 3142, 2559,
+ 1328, 2091, 2896, 768, 3705, 1066, 3184, 227, 2174, 3315, 3444, 168, 3012, 2873,
+ 2287, 2585, 3439, 3720, 2461, 815, 850, 3035, 802, 3348, 3699, 2864, 1015, 3178,
+ 1144, 3621, 2045, 3356, 1793, 1870, 2745, 550, 3654, 1373, 3653, 3687, 3236, 2760,
+ 1995, 1337, 3703, 3375, 2925, 3570, 3239, 3563, 3068, 3765, 3415, 1394, 2905, 3190,
+ 1223, 2870, 3197, 3366, 3368, 1648, 194, 2142, 2568, 3390, 2240, 2029, 3639, 3241,
+ 1822, 3025, 1630, 2413, 3643, 2724, 558, 2752, 2251, 2979, 3070, 2997, 3017, 2105,
+ 3190, 3559, 3762, 3337, 3087, 3494, 2808, 3126, 1800, 3109, 3804, 1040, 2418, 3233,
+ 2616, 1783, 3155, 1950, 2406, 3678, 3714, 3237, 3641, 3216, 2601, 1685, 3300, 3681,
+ 3030, 36, 1241, 1864, 520, 3305, 1622, 2582, 1333, 3176, 775, 3835, 2397, 2493,
+ 2466, 3471, 1337, 3827, 2298, 3846, 3444, 3818, 1586, 2712, 402, 2765, 2259, 1639,
+ 1066, 3787, 2836, 758, 3608, 2271, 399, 2943, 1712, 2736, 3656, 1345, 3594, 1382,
+ 624, 349, 2777, 71, 3740, 501, 1989, 1402, 2028, 449, 1984, 3091, 437, 2927, 3124,
+ 2515, 3856, 2, 3386, 3570, 1938, 2889, 2161, 3839, 575, 1536, 3080, 1811, 3895,
+ 2440, 3829, 1049, 887, 3431, 3824, 3878, 3864, 662, 3808, 3489, 3785, 2410, 3899,
+ 2697, 1389, 2079, 2094, 1599, 3766, 3819, 3919, 3873, 2841, 3921, 3868, 2214, 3371,
+ 2377, 2872, 1957, 3858, 1804, 3479, 1230, 3383, 456, 3572, 3918, 2468, 1153, 1961,
+ 3286, 3734, 2458, 2457, 3944, 3668, 3205, 1744, 9, 3899, 923, 890, 2710, 1022,
+ 3574, 3562, 1232, 1601, 2337, 3406, 3473, 3601, 1580, 3462, 0, 3268, 3290, 2073,
+ 2763, 1929, 3747, 659, 3692, 3555, 3758, 3605, 3220, 3153, 1570, 3333, 1437, 2664,
+ 2211, 1621, 3835, 2955, 3565, 3917, 1179, 3880, 1682, 439, 2077, 2153, 3976, 3962,
+ 62, 370, 2051, 3135, 3724, 2903, 3768, 3535, 2539, 3504, 1636, 3941, 422, 66, 2069,
+ 3188, 1213, 302, 2374, 3028, 3050, 3948, 4018, 1230, 3408, 3512, 2028, 2495, 4011,
+ 890, 1845, 3940, 3627, 1185, 1782, 3486, 3807, 1924, 854, 3047, 3497, 3875, 1892,
+ 687, 4027, 2591, 3639, 4032, 3278, 3094, 502, 3705, 1079, 3161, 4047, 3553, 2777,
+ 3264, 1325, 3845, 851, 3968, 3631, 3301, 2450, 519, 2243, 3689, 1142, 694, 3529,
+ 2267, 2057, 4037, 807, 3706, 2217, 2864, 3956, 3116, 1907, 4064, 3217, 3775, 3238,
+ 688, 1143, 599, 3050, 3856, 3094, 2281, 356, 3916, 3918, 3209, 349, 1317,
+ ];
+
+ let mut idx = offset;
+ for expected in expected_ref_idx.iter() {
+ // Mimic offset..segment_length runs with idx
+ assert_eq!(
+ *expected,
+ gidx.get_next(idx, &mut tmp_block),
+ "Invalid at {}",
+ idx
+ );
+ idx += 1;
+ }
+ }
+ }
+
+ mod test_g {
+ use super::*;
+
+ #[test]
+ fn g_test() {
+ let mut w0: u64 = 15555726891008754466;
+ let mut w1: u64 = 5510367530937399982;
+ let mut w2: u64 = 11481008432838211339;
+ let mut w3: u64 = 8667059981748828325;
+
+ let r0: u64 = 12666226408741176632;
+ let r1: u64 = 839899491230516963;
+ let r2: u64 = 17298398443694995777;
+ let r3: u64 = 10383764314571024184;
+
+ g(&mut w0, &mut w1, &mut w2, &mut w3);
+
+ assert_eq!(w0, r0);
+ assert_eq!(w1, r1);
+ assert_eq!(w2, r2);
+ assert_eq!(w3, r3);
+ }
+ }
+
+ mod test_p {
+ use super::*;
+
+ #[test]
+ fn p_test() {
+ let mut v0: u64 = 862185360016812330;
+ let mut v1: u64 = 9264562855185177247;
+ let mut v2: u64 = 17733520444968542606;
+ let mut v3: u64 = 13219822890422175473;
+ let mut v4: u64 = 6801067205434763034;
+ let mut v5: u64 = 10578543507696639262;
+ let mut v6: u64 = 10108704228654865903;
+ let mut v7: u64 = 2299791359568756431;
+ let mut v8: u64 = 15201093463674093404;
+ let mut v9: u64 = 13723714563716750079;
+ let mut v10: u64 = 9719717710557384967;
+ let mut v11: u64 = 1845563056782807427;
+ let mut v12: u64 = 1829242492466781631;
+ let mut v13: u64 = 17659944659119723559;
+ let mut v14: u64 = 14852831888916040100;
+ let mut v15: u64 = 12286853237524317048;
+
+ let r0: u64 = 560590257705063197;
+ let r1: u64 = 9520578903939690713;
+ let r2: u64 = 3436672759520932446;
+ let r3: u64 = 14405027955696943046;
+ let r4: u64 = 17277966793721620420;
+ let r5: u64 = 3246848157586690114;
+ let r6: u64 = 13237761561989265024;
+ let r7: u64 = 9829692378347117758;
+ let r8: u64 = 1155007077473720963;
+ let r9: u64 = 10252695060491707233;
+ let r10: u64 = 10189249967016125740;
+ let r11: u64 = 14693238843422479195;
+ let r12: u64 = 13413025648622208818;
+ let r13: u64 = 16791374424966705294;
+ let r14: u64 = 11596653054387906253;
+ let r15: u64 = 12616166200637387407;
+
+ permutation_p(
+ &mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8,
+ &mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15,
+ );
+
+ assert_eq!(v0, r0);
+ assert_eq!(v1, r1);
+ assert_eq!(v2, r2);
+ assert_eq!(v3, r3);
+ assert_eq!(v4, r4);
+ assert_eq!(v5, r5);
+ assert_eq!(v6, r6);
+ assert_eq!(v7, r7);
+ assert_eq!(v8, r8);
+ assert_eq!(v9, r9);
+ assert_eq!(v10, r10);
+ assert_eq!(v11, r11);
+ assert_eq!(v12, r12);
+ assert_eq!(v13, r13);
+ assert_eq!(v14, r14);
+ assert_eq!(v15, r15);
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/kdf/hkdf.rs b/vendor/orion/src/hazardous/kdf/hkdf.rs
new file mode 100644
index 0000000..371566a
--- /dev/null
+++ b/vendor/orion/src/hazardous/kdf/hkdf.rs
@@ -0,0 +1,522 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `salt`: Salt value.
+//! - `ikm`: Input keying material.
+//! - `info`: Optional context and application-specific information. If [`None`]
+//! then it's an empty string.
+//! - `dst_out`: Destination buffer for the derived key. The length of the
+//! derived key is implied by the length of `okm_out`.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The length of `dst_out` is less than 1.
+//! - The length of `dst_out` is greater than 255 * SHA(256/384/512)_OUTSIZE.
+//!
+//! # Security:
+//! - Salts should always be generated using a CSPRNG.
+//! [`secure_rand_bytes()`] can be used for this.
+//! - The recommended length for a salt is 64 bytes.
+//! - Even though a salt value is optional, it is strongly recommended to use one.
+//! - HKDF is not suitable for password storage.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::{hazardous::kdf::hkdf, util};
+//!
+//! let mut salt = [0u8; 64];
+//! util::secure_rand_bytes(&mut salt)?;
+//! let mut okm_out = [0u8; 32];
+//!
+//! hkdf::sha512::derive_key(&salt, "IKM".as_bytes(), None, &mut okm_out)?;
+//!
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`secure_rand_bytes()`]: crate::util::secure_rand_bytes
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::mac::hmac;
+use zeroize::Zeroize;
+
+/// The HKDF extract step.
+///
+/// NOTE: Hmac has the output size of the hash function defined,
+/// but the array initialization with the size cannot depend on a generic parameter,
+/// because we don't have full support for const generics yet.
+fn _extract<Hmac, const OUTSIZE: usize>(
+ salt: &[u8],
+ ikm: &[u8],
+) -> Result<[u8; OUTSIZE], UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ debug_assert_eq!(OUTSIZE, Hmac::HASH_FUNC_OUTSIZE);
+ let mut dest = [0u8; OUTSIZE];
+
+ let mut ctx = Hmac::_new(salt)?;
+ ctx._update(ikm)?;
+ ctx._finalize(&mut dest)?;
+
+ Ok(dest)
+}
+
+/// The HKDF expand step.
+fn _expand<Hmac, const OUTSIZE: usize>(
+ prk: &[u8],
+ info: Option<&[u8]>,
+ dest: &mut [u8],
+) -> Result<(), UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ debug_assert_eq!(OUTSIZE, Hmac::HASH_FUNC_OUTSIZE);
+ debug_assert_eq!(prk.len(), Hmac::HASH_FUNC_OUTSIZE);
+ if dest.is_empty() || dest.len() > 255 * Hmac::HASH_FUNC_OUTSIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ let optional_info = info.unwrap_or(&[0u8; 0]);
+ let mut ctx = Hmac::_new(prk)?;
+
+ // We require a temporary buffer in case the requested bytes
+ // to derive are lower than the HMAC functions output size.
+ let mut tmp = [0u8; OUTSIZE];
+ let mut idx: u8 = 1;
+ for hlen_block in dest.chunks_mut(Hmac::HASH_FUNC_OUTSIZE) {
+ ctx._update(optional_info)?;
+ ctx._update(&[idx])?;
+ debug_assert!(!hlen_block.is_empty() && hlen_block.len() <= Hmac::HASH_FUNC_OUTSIZE);
+ ctx._finalize(&mut tmp)?;
+ hlen_block.copy_from_slice(&tmp[..hlen_block.len()]);
+
+ if hlen_block.len() < Hmac::HASH_FUNC_OUTSIZE {
+ break;
+ }
+ match idx.checked_add(1) {
+ Some(next) => {
+ idx = next;
+ ctx._reset();
+ ctx._update(hlen_block)?;
+ }
+ // If `idx` reaches 255, the maximum (255 * Hmac::HASH_FUNC_OUTSIZE)
+ // amount of blocks have been processed.
+ None => break,
+ };
+ }
+
+ tmp.iter_mut().zeroize();
+
+ Ok(())
+}
+
+/// Combine `extract` and `expand` to return a derived key.
+///
+/// NOTE: See comment about const param at _extract function.
+fn _derive_key<Hmac, const OUTSIZE: usize>(
+ salt: &[u8],
+ ikm: &[u8],
+ info: Option<&[u8]>,
+ dest: &mut [u8],
+) -> Result<(), UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ _expand::<Hmac, { OUTSIZE }>(&_extract::<Hmac, { OUTSIZE }>(salt, ikm)?, info, dest)
+}
+
+/// HKDF-HMAC-SHA256 (HMAC-based Extract-and-Expand Key Derivation Function) as specified in the [RFC 5869](https://tools.ietf.org/html/rfc5869).
+pub mod sha256 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha256::SHA256_OUTSIZE;
+ pub use crate::hazardous::mac::hmac::sha256::Tag;
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF extract step.
+ pub fn extract(salt: &[u8], ikm: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ Ok(Tag::from(_extract::<
+ hmac::sha256::HmacSha256,
+ { SHA256_OUTSIZE },
+ >(salt, ikm)?))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF expand step.
+ pub fn expand(
+ prk: &Tag,
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _expand::<hmac::sha256::HmacSha256, { SHA256_OUTSIZE }>(
+ prk.unprotected_as_bytes(),
+ info,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Combine `extract` and `expand` to return a derived key.
+ pub fn derive_key(
+ salt: &[u8],
+ ikm: &[u8],
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha256::HmacSha256, { SHA256_OUTSIZE }>(salt, ikm, info, dst_out)
+ }
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ // Mark safe_api because currently it only contains proptests.
+ mod test_derive_key {
+ use crate::hazardous::hash::sha2::sha256::SHA256_OUTSIZE;
+
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Using derive_key() should always yield the same result
+ /// as using extract and expand separately.
+ fn prop_test_derive_key_same_separate(
+ salt: Vec<u8>,
+ ikm: Vec<u8>,
+ info: Vec<u8>,
+ outsize: usize,
+ ) -> bool {
+ let outsize_checked = if outsize == 0 || outsize > 255 * SHA256_OUTSIZE {
+ 64
+ } else {
+ outsize
+ };
+
+ let prk = extract(&salt[..], &ikm[..]).unwrap();
+ let mut out = vec![0u8; outsize_checked];
+ expand(&prk, Some(&info[..]), &mut out).unwrap();
+
+ let mut out_one_shot = vec![0u8; outsize_checked];
+ derive_key(&salt[..], &ikm[..], Some(&info[..]), &mut out_one_shot).unwrap();
+
+ out == out_one_shot
+ }
+ }
+}
+
+/// HKDF-HMAC-SHA384 (HMAC-based Extract-and-Expand Key Derivation Function) as specified in the [RFC 5869](https://tools.ietf.org/html/rfc5869).
+pub mod sha384 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha384::SHA384_OUTSIZE;
+ pub use crate::hazardous::mac::hmac::sha384::Tag;
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF extract step.
+ pub fn extract(salt: &[u8], ikm: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ Ok(Tag::from(_extract::<
+ hmac::sha384::HmacSha384,
+ { SHA384_OUTSIZE },
+ >(salt, ikm)?))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF expand step.
+ pub fn expand(
+ prk: &Tag,
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _expand::<hmac::sha384::HmacSha384, { SHA384_OUTSIZE }>(
+ prk.unprotected_as_bytes(),
+ info,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Combine `extract` and `expand` to return a derived key.
+ pub fn derive_key(
+ salt: &[u8],
+ ikm: &[u8],
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha384::HmacSha384, { SHA384_OUTSIZE }>(salt, ikm, info, dst_out)
+ }
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ // Mark safe_api because currently it only contains proptests.
+ mod test_derive_key {
+ use crate::hazardous::hash::sha2::sha384::SHA384_OUTSIZE;
+
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Using derive_key() should always yield the same result
+ /// as using extract and expand separately.
+ fn prop_test_derive_key_same_separate(
+ salt: Vec<u8>,
+ ikm: Vec<u8>,
+ info: Vec<u8>,
+ outsize: usize,
+ ) -> bool {
+ let outsize_checked = if outsize == 0 || outsize > 255 * SHA384_OUTSIZE {
+ 64
+ } else {
+ outsize
+ };
+
+ let prk = extract(&salt[..], &ikm[..]).unwrap();
+ let mut out = vec![0u8; outsize_checked];
+ expand(&prk, Some(&info[..]), &mut out).unwrap();
+
+ let mut out_one_shot = vec![0u8; outsize_checked];
+ derive_key(&salt[..], &ikm[..], Some(&info[..]), &mut out_one_shot).unwrap();
+
+ out == out_one_shot
+ }
+ }
+}
+
+/// HKDF-HMAC-SHA512 (HMAC-based Extract-and-Expand Key Derivation Function) as specified in the [RFC 5869](https://tools.ietf.org/html/rfc5869).
+pub mod sha512 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha512::SHA512_OUTSIZE;
+ pub use crate::hazardous::mac::hmac::sha512::Tag;
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF extract step.
+ pub fn extract(salt: &[u8], ikm: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ Ok(Tag::from(_extract::<
+ hmac::sha512::HmacSha512,
+ { SHA512_OUTSIZE },
+ >(salt, ikm)?))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// The HKDF expand step.
+ pub fn expand(
+ prk: &Tag,
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _expand::<hmac::sha512::HmacSha512, { SHA512_OUTSIZE }>(
+ prk.unprotected_as_bytes(),
+ info,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Combine `extract` and `expand` to return a derived key.
+ pub fn derive_key(
+ salt: &[u8],
+ ikm: &[u8],
+ info: Option<&[u8]>,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha512::HmacSha512, { SHA512_OUTSIZE }>(salt, ikm, info, dst_out)
+ }
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ // Mark safe_api because currently it only contains proptests.
+ mod test_derive_key {
+ use crate::hazardous::hash::sha2::sha512::SHA512_OUTSIZE;
+
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Using derive_key() should always yield the same result
+ /// as using extract and expand separately.
+ fn prop_test_derive_key_same_separate(
+ salt: Vec<u8>,
+ ikm: Vec<u8>,
+ info: Vec<u8>,
+ outsize: usize,
+ ) -> bool {
+ let outsize_checked = if outsize == 0 || outsize > 255 * SHA512_OUTSIZE {
+ 64
+ } else {
+ outsize
+ };
+
+ let prk = extract(&salt[..], &ikm[..]).unwrap();
+ let mut out = vec![0u8; outsize_checked];
+ expand(&prk, Some(&info[..]), &mut out).unwrap();
+
+ let mut out_one_shot = vec![0u8; outsize_checked];
+ derive_key(&salt[..], &ikm[..], Some(&info[..]), &mut out_one_shot).unwrap();
+
+ out == out_one_shot
+ }
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+ use crate::hazardous::hash::sha2::{
+ sha256::SHA256_OUTSIZE, sha384::SHA384_OUTSIZE, sha512::SHA512_OUTSIZE,
+ };
+
+ #[test]
+ fn hkdf_above_maximum_length_err() {
+ let mut okm_out = [0u8; 255 * SHA256_OUTSIZE + 1];
+ let prk = sha256::extract(b"", b"").unwrap();
+ assert!(sha256::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha256::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+
+ let mut okm_out = [0u8; 255 * SHA384_OUTSIZE + 1];
+ let prk = sha384::extract(b"", b"").unwrap();
+ assert!(sha384::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha384::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+
+ let mut okm_out = [0u8; 255 * SHA512_OUTSIZE + 1];
+ let prk = sha512::extract(b"", b"").unwrap();
+ assert!(sha512::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha512::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+ }
+
+ #[test]
+ fn hkdf_exact_maximum_length_ok() {
+ let mut okm_out = [0u8; 255 * SHA256_OUTSIZE];
+ let prk = sha256::extract(b"", b"").unwrap();
+ assert!(sha256::expand(&prk, Some(b""), &mut okm_out).is_ok());
+ assert!(sha256::derive_key(b"", b"", Some(b""), &mut okm_out).is_ok());
+
+ let mut okm_out = [0u8; 255 * SHA384_OUTSIZE];
+ let prk = sha384::extract(b"", b"").unwrap();
+ assert!(sha384::expand(&prk, Some(b""), &mut okm_out).is_ok());
+ assert!(sha384::derive_key(b"", b"", Some(b""), &mut okm_out).is_ok());
+
+ let mut okm_out = [0u8; 255 * SHA512_OUTSIZE];
+ let prk = sha512::extract(b"", b"").unwrap();
+ assert!(sha512::expand(&prk, Some(b""), &mut okm_out).is_ok());
+ assert!(sha512::derive_key(b"", b"", Some(b""), &mut okm_out).is_ok());
+ }
+
+ #[test]
+ fn hkdf_zero_length_err() {
+ let mut okm_out = [0u8; 0];
+
+ let prk = sha256::extract(b"", b"").unwrap();
+ assert!(sha256::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha256::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+
+ let prk = sha384::extract(b"", b"").unwrap();
+ assert!(sha384::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha384::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+
+ let prk = sha512::extract(b"", b"").unwrap();
+ assert!(sha512::expand(&prk, Some(b""), &mut okm_out).is_err());
+ assert!(sha512::derive_key(b"", b"", Some(b""), &mut okm_out).is_err());
+ }
+
+ #[test]
+ fn hkdf_info_param() {
+ // Test that using None or empty array as info is the same.
+ let mut okm_out = [0u8; 32];
+ let mut okm_out_verify = [0u8; 32];
+
+ let prk = sha256::extract(b"", b"").unwrap();
+ assert!(sha256::expand(&prk, Some(b""), &mut okm_out).is_ok()); // Use info Some
+ assert!(sha256::derive_key(b"", b"", None, &mut okm_out_verify).is_ok());
+ assert_eq!(okm_out, okm_out_verify);
+
+ let prk = sha384::extract(b"", b"").unwrap();
+ assert!(sha384::expand(&prk, Some(b""), &mut okm_out).is_ok()); // Use info Some
+ assert!(sha384::derive_key(b"", b"", None, &mut okm_out_verify).is_ok());
+ assert_eq!(okm_out, okm_out_verify);
+
+ let prk = sha512::extract(b"", b"").unwrap();
+ assert!(sha512::expand(&prk, Some(b""), &mut okm_out).is_ok()); // Use info Some
+ assert!(sha512::derive_key(b"", b"", None, &mut okm_out_verify).is_ok());
+ assert_eq!(okm_out, okm_out_verify);
+ }
+
+ #[test]
+ fn hkdf_wrong_salt() {
+ let ikm = b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
+ let salt = b"000102030405060708090a0b0c";
+ let info = b"f0f1f2f3f4f5f6f7f8f9";
+ let mut okm_out = [0u8; 42];
+ let mut okm_out_verify = [0u8; 42];
+
+ sha256::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha256::derive_key(b"", ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+
+ sha384::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha384::derive_key(b"", ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+
+ sha512::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha512::derive_key(b"", ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+ }
+
+ #[test]
+ fn hkdf_verify_wrong_ikm() {
+ let ikm = b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
+ let salt = b"000102030405060708090a0b0c";
+ let info = b"f0f1f2f3f4f5f6f7f8f9";
+ let mut okm_out = [0u8; 42];
+ let mut okm_out_verify = [0u8; 42];
+
+ sha256::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha256::derive_key(salt, b"", Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+
+ sha384::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha384::derive_key(salt, b"", Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+
+ sha512::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha512::derive_key(salt, b"", Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out, okm_out_verify);
+ }
+
+ #[test]
+ fn verify_diff_length() {
+ let ikm = b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
+ let salt = b"000102030405060708090a0b0c";
+ let info = b"f0f1f2f3f4f5f6f7f8f9";
+ let mut okm_out = [0u8; 42];
+ let mut okm_out_verify = [0u8; 43];
+
+ sha256::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha256::derive_key(salt, ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out[..], okm_out_verify[..]);
+
+ sha384::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha384::derive_key(salt, ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out[..], okm_out_verify[..]);
+
+ sha512::derive_key(salt, ikm, Some(info), &mut okm_out).unwrap();
+ sha512::derive_key(salt, ikm, Some(info), &mut okm_out_verify).unwrap();
+ assert_ne!(okm_out[..], okm_out_verify[..]);
+ }
+}
diff --git a/vendor/orion/src/hazardous/kdf/mod.rs b/vendor/orion/src/hazardous/kdf/mod.rs
new file mode 100644
index 0000000..2806876
--- /dev/null
+++ b/vendor/orion/src/hazardous/kdf/mod.rs
@@ -0,0 +1,31 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// HKDF (HMAC-based Extract-and-Expand Key Derivation Function) as specified in the [RFC 5869](https://tools.ietf.org/html/rfc5869).
+pub mod hkdf;
+
+/// PBKDF2(Password-Based Key Derivation Function 2) as specified in the [RFC 8018](https://tools.ietf.org/html/rfc8018).
+pub mod pbkdf2;
+
+#[cfg(any(feature = "safe_api", feature = "alloc"))]
+/// Argon2i password hashing function as described in the [P-H-C specification](https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf).
+pub mod argon2i;
diff --git a/vendor/orion/src/hazardous/kdf/pbkdf2.rs b/vendor/orion/src/hazardous/kdf/pbkdf2.rs
new file mode 100644
index 0000000..9ed23b0
--- /dev/null
+++ b/vendor/orion/src/hazardous/kdf/pbkdf2.rs
@@ -0,0 +1,579 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `password`: Password.
+//! - `salt`: Salt value.
+//! - `iterations`: Iteration count.
+//! - `dst_out`: Destination buffer for the derived key. The length of the
+//! derived key is implied by the length of `dst_out`.
+//! - `expected`: The expected derived key.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The length of `dst_out` is less than 1.
+//! - The specified iteration count is less than 1.
+//! - The hashed password does not match the expected when verifying.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - The length of `dst_out` is greater than (2^32 - 1) * SHA(256/384/512)_OUTSIZE.
+//!
+//! # Security:
+//! - Use [`Password::generate()`] to randomly generate a password of the same length as
+//! the underlying SHA2 hash functions blocksize.
+//! - Salts should always be generated using a CSPRNG.
+//! [`secure_rand_bytes()`] can be used for this.
+//! - The recommended length for a salt is 64 bytes.
+//! - The iteration count should be set as high as feasible. Please check [OWASP] for
+//! the recommended minimum amount (600000 at the time of writing).
+//! - Please note that when verifying, a copy of the computed password hash is placed into
+//! `dst_out`. If the derived hash is considered sensitive and you want to provide defense
+//! in depth against an attacker reading your application's private memory, then you as
+//! the user are responsible for zeroing out this buffer (see the [`zeroize` crate]).
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::{hazardous::kdf::pbkdf2, util};
+//!
+//! let mut salt = [0u8; 64];
+//! util::secure_rand_bytes(&mut salt)?;
+//! let password = pbkdf2::sha512::Password::from_slice("Secret password".as_bytes())?;
+//! let mut dst_out = [0u8; 64];
+//!
+//! pbkdf2::sha512::derive_key(&password, &salt, 10000, &mut dst_out)?;
+//!
+//! let expected_dk = dst_out;
+//!
+//! assert!(pbkdf2::sha512::verify(&expected_dk, &password, &salt, 10000, &mut dst_out).is_ok());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`Password::generate()`]: pbkdf2::sha512::Password::generate
+//! [`secure_rand_bytes()`]: crate::util::secure_rand_bytes
+//! [`zeroize` crate]: https://crates.io/crates/zeroize
+//! [OWASP]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
+
+use crate::{errors::UnknownCryptoError, hazardous::mac::hmac};
+
+/// The F function as described in the RFC.
+fn _function_f<Hmac>(
+ salt: &[u8],
+ iterations: usize,
+ index: u32,
+ dk_block: &mut [u8],
+ block_len: usize,
+ u_step: &mut [u8],
+ hmac: &mut Hmac,
+) -> Result<(), UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ debug_assert_eq!(u_step.len(), Hmac::HASH_FUNC_OUTSIZE);
+ hmac._update(salt)?;
+ hmac._update(&index.to_be_bytes())?;
+ hmac._finalize(u_step)?;
+ debug_assert!(block_len <= u_step.len());
+ dk_block.copy_from_slice(&u_step[..block_len]);
+
+ if iterations > 1 {
+ for _ in 1..iterations {
+ hmac._reset();
+ hmac._update(u_step)?;
+ hmac._finalize(u_step)?;
+ xor_slices!(u_step, dk_block);
+ }
+ }
+
+ Ok(())
+}
+
+///
+///
+/// NOTE: Hmac has the output size of the hash function defined,
+/// but the array initialization with the size cannot depend on a generic parameter,
+/// because we don't have full support for const generics yet.
+fn _derive_key<Hmac, const OUTSIZE: usize>(
+ padded_password: &[u8],
+ salt: &[u8],
+ iterations: usize,
+ dest: &mut [u8],
+) -> Result<(), UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ debug_assert_eq!(OUTSIZE, Hmac::HASH_FUNC_OUTSIZE);
+ if dest.is_empty() || iterations < 1 {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut u_step = [0u8; OUTSIZE];
+ let mut hmac = Hmac::_new(padded_password)?;
+ for (idx, dk_block) in dest.chunks_mut(Hmac::HASH_FUNC_OUTSIZE).enumerate() {
+ // If this panics, then the size limit for PBKDF2 is reached.
+ let block_idx: u32 = 1u32.checked_add(idx as u32).unwrap();
+
+ _function_f(
+ salt,
+ iterations,
+ block_idx,
+ dk_block,
+ dk_block.len(),
+ &mut u_step,
+ &mut hmac,
+ )?;
+
+ hmac._reset();
+ }
+
+ Ok(())
+}
+
+///
+///
+/// NOTE: Hmac has the output size of the hash function defined,
+/// but the array initialization with the size cannot depend on a generic parameter,
+/// because we don't have full support for const generics yet.
+fn _verify<Hmac, const OUTSIZE: usize>(
+ expected: &[u8],
+ padded_password: &[u8],
+ salt: &[u8],
+ iterations: usize,
+ dest: &mut [u8],
+) -> Result<(), UnknownCryptoError>
+where
+ Hmac: hmac::HmacFunction,
+{
+ debug_assert_eq!(OUTSIZE, Hmac::HASH_FUNC_OUTSIZE);
+ _derive_key::<Hmac, { OUTSIZE }>(padded_password, salt, iterations, dest)?;
+ crate::util::secure_cmp(expected, dest)
+}
+
+/// PBKDF2-HMAC-SHA256 (Password-Based Key Derivation Function 2) as specified in the [RFC 8018](https://tools.ietf.org/html/rfc8018).
+pub mod sha256 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha256::{self, Sha256};
+
+ construct_hmac_key! {
+ /// A type to represent the `Password` that PBKDF2 hashes.
+ ///
+ /// # Note:
+ /// Because `Password` is used as a `SecretKey` for HMAC during hashing, `Password` already
+ /// pads the given password to a length of 64, for use in HMAC, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the password with padding.
+ ///
+ /// Using `get_length()` will return the length with padding (always 64).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Password, Sha256, sha256::SHA256_OUTSIZE, test_pbkdf2_password, sha256::SHA256_BLOCKSIZE)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Derive a key using PBKDF2-HMAC-SHA256.
+ pub fn derive_key(
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha256::HmacSha256, { sha256::SHA256_OUTSIZE }>(
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify PBKDF2-HMAC-SHA256 derived key in constant time.
+ pub fn verify(
+ expected: &[u8],
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _verify::<hmac::sha256::HmacSha256, { sha256::SHA256_OUTSIZE }>(
+ expected,
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+}
+
+/// PBKDF2-HMAC-SHA384 (Password-Based Key Derivation Function 2) as specified in the [RFC 8018](https://tools.ietf.org/html/rfc8018).
+pub mod sha384 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha384::{self, Sha384};
+
+ construct_hmac_key! {
+ /// A type to represent the `Password` that PBKDF2 hashes.
+ ///
+ /// # Note:
+ /// Because `Password` is used as a `SecretKey` for HMAC during hashing, `Password` already
+ /// pads the given password to a length of 128, for use in HMAC, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the password with padding.
+ ///
+ /// Using `get_length()` will return the length with padding (always 128).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Password, Sha384, sha384::SHA384_OUTSIZE, test_pbkdf2_password, sha384::SHA384_BLOCKSIZE)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Derive a key using PBKDF2-HMAC-SHA384.
+ pub fn derive_key(
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha384::HmacSha384, { sha384::SHA384_OUTSIZE }>(
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify PBKDF2-HMAC-SHA384 derived key in constant time.
+ pub fn verify(
+ expected: &[u8],
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _verify::<hmac::sha384::HmacSha384, { sha384::SHA384_OUTSIZE }>(
+ expected,
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+}
+
+/// PBKDF2-HMAC-SHA512 (Password-Based Key Derivation Function 2) as specified in the [RFC 8018](https://tools.ietf.org/html/rfc8018).
+pub mod sha512 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha512::{self, Sha512};
+
+ construct_hmac_key! {
+ /// A type to represent the `Password` that PBKDF2 hashes.
+ ///
+ /// # Note:
+ /// Because `Password` is used as a `SecretKey` for HMAC during hashing, `Password` already
+ /// pads the given password to a length of 128, for use in HMAC, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the password with padding.
+ ///
+ /// Using `get_length()` will return the length with padding (always 128).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Password, Sha512, sha512::SHA512_OUTSIZE, test_pbkdf2_password, sha512::SHA512_BLOCKSIZE)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Derive a key using PBKDF2-HMAC-SHA512.
+ pub fn derive_key(
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _derive_key::<hmac::sha512::HmacSha512, { sha512::SHA512_OUTSIZE }>(
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify PBKDF2-HMAC-SHA512 derived key in constant time.
+ pub fn verify(
+ expected: &[u8],
+ password: &Password,
+ salt: &[u8],
+ iterations: usize,
+ dst_out: &mut [u8],
+ ) -> Result<(), UnknownCryptoError> {
+ _verify::<hmac::sha512::HmacSha512, { sha512::SHA512_OUTSIZE }>(
+ expected,
+ password.unprotected_as_bytes(),
+ salt,
+ iterations,
+ dst_out,
+ )
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ mod test_verify {
+ use super::*;
+
+ #[test]
+ fn verify_true() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "sa\0lt".as_bytes();
+ let iterations: usize = 128;
+ let mut okm_out = [0u8; 16];
+ let mut okm_out_verify = [0u8; 16];
+
+ sha256::derive_key(&password_256, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha256::verify(
+ &okm_out,
+ &password_256,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_ok());
+
+ sha384::derive_key(&password_384, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha384::verify(
+ &okm_out,
+ &password_384,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_ok());
+
+ sha512::derive_key(&password_512, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha512::verify(
+ &okm_out,
+ &password_512,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_ok());
+ }
+
+ #[test]
+ fn verify_false_wrong_salt() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "sa\0lt".as_bytes();
+ let iterations: usize = 128;
+ let mut okm_out = [0u8; 16];
+ let mut okm_out_verify = [0u8; 16];
+
+ sha256::derive_key(&password_256, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha256::verify(
+ &okm_out,
+ &password_256,
+ b"",
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha384::derive_key(&password_384, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha384::verify(
+ &okm_out,
+ &password_384,
+ b"",
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha512::derive_key(&password_512, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha512::verify(
+ &okm_out,
+ &password_512,
+ b"",
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+ }
+ #[test]
+ fn verify_false_wrong_password() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "sa\0lt".as_bytes();
+ let iterations: usize = 128;
+ let mut okm_out = [0u8; 16];
+ let mut okm_out_verify = [0u8; 16];
+
+ sha256::derive_key(&password_256, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha256::verify(
+ &okm_out,
+ &sha256::Password::from_slice(b"pass").unwrap(),
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha384::derive_key(&password_384, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha384::verify(
+ &okm_out,
+ &sha384::Password::from_slice(b"pass").unwrap(),
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha512::derive_key(&password_512, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha512::verify(
+ &okm_out,
+ &sha512::Password::from_slice(b"pass").unwrap(),
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn verify_diff_dklen_error() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "sa\0lt".as_bytes();
+ let iterations: usize = 128;
+ let mut okm_out = [0u8; 16];
+ let mut okm_out_verify = [0u8; 32];
+
+ sha256::derive_key(&password_256, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha256::verify(
+ &okm_out,
+ &password_256,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha384::derive_key(&password_384, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha384::verify(
+ &okm_out,
+ &password_384,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+
+ sha512::derive_key(&password_512, salt, iterations, &mut okm_out).unwrap();
+ assert!(sha512::verify(
+ &okm_out,
+ &password_512,
+ salt,
+ iterations,
+ &mut okm_out_verify
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn verify_diff_iter_error() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "sa\0lt".as_bytes();
+ let iterations: usize = 128;
+ let mut okm_out = [0u8; 16];
+ let mut okm_out_verify = [0u8; 16];
+
+ sha256::derive_key(&password_256, salt, iterations, &mut okm_out).unwrap();
+ assert!(
+ sha256::verify(&okm_out, &password_256, salt, 127, &mut okm_out_verify).is_err()
+ );
+
+ sha384::derive_key(&password_384, salt, iterations, &mut okm_out).unwrap();
+ assert!(
+ sha384::verify(&okm_out, &password_384, salt, 127, &mut okm_out_verify).is_err()
+ );
+
+ sha512::derive_key(&password_512, salt, iterations, &mut okm_out).unwrap();
+ assert!(
+ sha512::verify(&okm_out, &password_512, salt, 127, &mut okm_out_verify).is_err()
+ );
+ }
+ }
+
+ mod test_derive_key {
+ use super::*;
+
+ #[test]
+ fn zero_iterations_err() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "salt".as_bytes();
+ let iterations: usize = 0;
+ let mut okm_out = [0u8; 15];
+
+ assert!(sha256::derive_key(&password_256, salt, iterations, &mut okm_out).is_err());
+ assert!(sha384::derive_key(&password_384, salt, iterations, &mut okm_out).is_err());
+ assert!(sha512::derive_key(&password_512, salt, iterations, &mut okm_out).is_err());
+ }
+
+ #[test]
+ fn zero_dklen_err() {
+ let password_256 = sha256::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_384 = sha384::Password::from_slice("pass\0word".as_bytes()).unwrap();
+ let password_512 = sha512::Password::from_slice("pass\0word".as_bytes()).unwrap();
+
+ let salt = "salt".as_bytes();
+ let iterations: usize = 1;
+ let mut okm_out = [0u8; 0];
+
+ assert!(sha256::derive_key(&password_256, salt, iterations, &mut okm_out).is_err());
+ assert!(sha384::derive_key(&password_384, salt, iterations, &mut okm_out).is_err());
+ assert!(sha512::derive_key(&password_512, salt, iterations, &mut okm_out).is_err());
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/kem/mod.rs b/vendor/orion/src/hazardous/kem/mod.rs
new file mode 100644
index 0000000..767b653
--- /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 0000000..0ea9609
--- /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/blake2b.rs b/vendor/orion/src/hazardous/mac/blake2b.rs
new file mode 100644
index 0000000..9b9bfab
--- /dev/null
+++ b/vendor/orion/src/hazardous/mac/blake2b.rs
@@ -0,0 +1,435 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `secret_key`: The authentication key.
+//! - `size`: The desired output length for the authentication tag.
+//! - `data`: Data to be authenticated.
+//! - `expected`: The expected authentication tag.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - `size` is 0 or greater than 64.
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) bytes of data are hashed.
+//!
+//! # Security:
+//! - The secret key should always be generated using a CSPRNG.
+//! [`SecretKey::generate()`] can be used for this. It generates
+//! a secret key of 32 bytes.
+//! - The minimum recommended size for a secret key is 32 bytes.
+//! - The recommended minimum output size is 32.
+//! - This interface only allows creating authentication tag using BLAKE2b. If hash digests are needed,
+//! please refer to the [`hash::blake2::blake2b`] module.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::mac::blake2b::{Blake2b, SecretKey};
+//!
+//! let key = SecretKey::generate();
+//!
+//! let mut state = Blake2b::new(&key, 64)?;
+//! state.update(b"Some data")?;
+//! let tag = state.finalize()?;
+//!
+//! assert!(Blake2b::verify(&tag, &key, 64, b"Some data").is_ok());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: blake2b::Blake2b::update
+//! [`reset()`]: blake2b::Blake2b::reset
+//! [`finalize()`]: blake2b::Blake2b::finalize
+//! [`SecretKey::generate()`]: blake2b::SecretKey::generate
+//! [`hash::blake2::blake2b`]: crate::hazardous::hash::blake2::blake2b
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::hash::blake2::blake2b_core::{self, BLAKE2B_KEYSIZE, BLAKE2B_OUTSIZE};
+use core::ops::DerefMut;
+use zeroize::Zeroizing;
+
+construct_secret_key! {
+ /// A type to represent the secret key that BLAKE2b uses for keyed mode.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `slice` is greater than 64 bytes.
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, test_secret_key, 1, BLAKE2B_KEYSIZE, 32)
+}
+
+construct_tag! {
+ /// A type to represent the `Tag` that BLAKE2b returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `slice` is greater than 64 bytes.
+ (Tag, test_tag, 1, BLAKE2B_OUTSIZE)
+}
+
+#[derive(Debug, Clone)]
+/// BLAKE2b streaming state.
+pub struct Blake2b {
+ _state: blake2b_core::State,
+}
+
+impl Blake2b {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize a `Blake2b` struct with a given size (in bytes) and key.
+ pub fn new(secret_key: &SecretKey, size: usize) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ _state: blake2b_core::State::_new(secret_key.unprotected_as_bytes(), size)?,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Reset to `new()` state.
+ pub fn reset(&mut self, secret_key: &SecretKey) -> Result<(), UnknownCryptoError> {
+ self._state._reset(secret_key.unprotected_as_bytes())
+ }
+
+ #[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)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a BLAKE2b tag.
+ pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ let mut tmp: Zeroizing<[u8; BLAKE2B_OUTSIZE]> = Zeroizing::new([0u8; BLAKE2B_OUTSIZE]);
+ self._state._finalize(tmp.deref_mut())?;
+
+ Tag::from_slice(&tmp[..self._state.size])
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify a BLAKE2b tag in constant time.
+ pub fn verify(
+ expected: &Tag,
+ secret_key: &SecretKey,
+ size: usize,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ let mut ctx = Self::new(secret_key, size)?;
+ ctx.update(data)?;
+
+ if &ctx.finalize()? == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+}
+
+#[cfg(test)]
+mod public {
+ mod test_streaming_interface_no_key {
+ use crate::errors::UnknownCryptoError;
+ use crate::hazardous::hash::blake2::blake2b_core::{
+ compare_blake2b_states, BLAKE2B_BLOCKSIZE, BLAKE2B_OUTSIZE,
+ };
+ use crate::hazardous::mac::blake2b::{Blake2b, SecretKey, Tag};
+ use crate::test_framework::incremental_interface::{
+ StreamingContextConsistencyTester, TestableStreamingContext,
+ };
+
+ const KEY: [u8; 32] = [255u8; 32];
+
+ impl TestableStreamingContext<Tag> for Blake2b {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ let key = SecretKey::from_slice(&KEY).unwrap();
+ self.reset(&key)
+ }
+
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(input)
+ }
+
+ fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ let key = SecretKey::from_slice(&KEY).unwrap();
+ let mut ctx = Blake2b::new(&key, BLAKE2B_OUTSIZE)?;
+ ctx.update(input)?;
+ ctx.finalize()
+ }
+
+ fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Blake2b, state_2: &Blake2b) {
+ compare_blake2b_states(&state_1._state, &state_2._state)
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let key = SecretKey::from_slice(&KEY).unwrap();
+ let initial_state: Blake2b = Blake2b::new(&key, BLAKE2B_OUTSIZE).unwrap();
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, Blake2b>::new(
+ initial_state,
+ BLAKE2B_BLOCKSIZE,
+ );
+ 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 key = SecretKey::from_slice(&KEY).unwrap();
+ let initial_state: Blake2b = Blake2b::new(&key, BLAKE2B_OUTSIZE).unwrap();
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, Blake2b>::new(
+ initial_state,
+ BLAKE2B_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ mod test_new {
+ use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
+
+ #[test]
+ fn test_init_size() {
+ let sk = SecretKey::from_slice(&[0u8; 32]).unwrap();
+ assert!(Blake2b::new(&sk, 0).is_err());
+ assert!(Blake2b::new(&sk, 65).is_err());
+ assert!(Blake2b::new(&sk, 1).is_ok());
+ assert!(Blake2b::new(&sk, 64).is_ok());
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different key, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
+ let sk = SecretKey::generate();
+ let mut state = Blake2b::new(&sk, 64).unwrap();
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+ let bad_sk = SecretKey::generate();
+
+ Blake2b::verify(&tag, &bad_sk, 64, &data[..]).is_err()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different size, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_size_false(data: Vec<u8>, size_one: usize, size_two: usize) -> bool {
+ let (size_one, size_two) = match (size_one, size_two) {
+ (1..=64, 1..=64) => (size_one, size_two),
+ (_, _) => (32, 64),
+ };
+
+ let sk = SecretKey::generate();
+ let mut state = Blake2b::new(&sk, size_one).unwrap();
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+
+ if size_one != size_two {
+ Blake2b::verify(&tag, &sk, size_two, &data[..]).is_err()
+ } else {
+ Blake2b::verify(&tag, &sk, size_two, &data[..]).is_ok()
+ }
+ }
+ }
+
+ mod test_streaming_interface {
+ use crate::hazardous::hash::blake2::blake2b_core::compare_blake2b_states;
+ use crate::hazardous::mac::blake2b::{Blake2b, SecretKey};
+
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Testing different usage combinations of new(), update(),
+ /// finalize() and reset() produce the same Digest/Tag.
+ fn produces_same_hash(sk: &SecretKey, size: usize, data: &[u8]) {
+ // new(), update(), finalize()
+ let mut state_1 = Blake2b::new(sk, size).unwrap();
+ state_1.update(data).unwrap();
+ let res_1 = state_1.finalize().unwrap();
+
+ // new(), reset(), update(), finalize()
+ let mut state_2 = Blake2b::new(sk, size).unwrap();
+ state_2.reset(sk).unwrap();
+ state_2.update(data).unwrap();
+ let res_2 = state_2.finalize().unwrap();
+
+ // new(), update(), reset(), update(), finalize()
+ let mut state_3 = Blake2b::new(sk, size).unwrap();
+ state_3.update(data).unwrap();
+ state_3.reset(sk).unwrap();
+ state_3.update(data).unwrap();
+ let res_3 = state_3.finalize().unwrap();
+
+ // new(), update(), finalize(), reset(), update(), finalize()
+ let mut state_4 = Blake2b::new(sk, size).unwrap();
+ state_4.update(data).unwrap();
+ let _ = state_4.finalize().unwrap();
+ state_4.reset(sk).unwrap();
+ state_4.update(data).unwrap();
+ let res_4 = state_4.finalize().unwrap();
+
+ assert_eq!(res_1, res_2);
+ assert_eq!(res_2, res_3);
+ assert_eq!(res_3, res_4);
+
+ // Tests for the assumption that returning Ok() on empty update() calls
+ // with streaming APIs, gives the correct result. This is done by testing
+ // the reasoning that if update() is empty, returns Ok(), it is the same as
+ // calling new() -> finalize(). i.e not calling update() at all.
+ if data.is_empty() {
+ // new(), finalize()
+ let mut state_5 = Blake2b::new(sk, size).unwrap();
+ let res_5 = state_5.finalize().unwrap();
+
+ // new(), reset(), finalize()
+ let mut state_6 = Blake2b::new(sk, size).unwrap();
+ state_6.reset(sk).unwrap();
+ let res_6 = state_6.finalize().unwrap();
+
+ // new(), update(), reset(), finalize()
+ let mut state_7 = Blake2b::new(sk, size).unwrap();
+ state_7.update(b"Wrong data").unwrap();
+ state_7.reset(sk).unwrap();
+ let res_7 = state_7.finalize().unwrap();
+
+ assert_eq!(res_4, res_5);
+ assert_eq!(res_5, res_6);
+ assert_eq!(res_6, res_7);
+ }
+ }
+
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Testing different usage combinations of new(), update(),
+ /// finalize() and reset() produce the same Digest/Tag.
+ fn produces_same_state(sk: &SecretKey, size: usize, data: &[u8]) {
+ // new()
+ let state_1 = Blake2b::new(sk, size).unwrap();
+
+ // new(), reset()
+ let mut state_2 = Blake2b::new(sk, size).unwrap();
+ state_2.reset(sk).unwrap();
+
+ // new(), update(), reset()
+ let mut state_3 = Blake2b::new(sk, size).unwrap();
+ state_3.update(data).unwrap();
+ state_3.reset(sk).unwrap();
+
+ // new(), update(), finalize(), reset()
+ let mut state_4 = Blake2b::new(sk, size).unwrap();
+ state_4.update(data).unwrap();
+ let _ = state_4.finalize().unwrap();
+ state_4.reset(sk).unwrap();
+
+ compare_blake2b_states(&state_1._state, &state_2._state);
+ compare_blake2b_states(&state_2._state, &state_3._state);
+ compare_blake2b_states(&state_3._state, &state_4._state);
+ }
+
+ #[test]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ fn test_produce_same_state() {
+ let sk = SecretKey::from_slice(b"Testing").unwrap();
+ produces_same_state(&sk, 1, b"Tests");
+ produces_same_state(&sk, 32, b"Tests");
+ produces_same_state(&sk, 64, b"Tests");
+ produces_same_state(&sk, 28, b"Tests");
+ }
+
+ #[test]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ fn test_produce_same_hash() {
+ let sk = SecretKey::from_slice(b"Testing").unwrap();
+ produces_same_hash(&sk, 1, b"Tests");
+ produces_same_hash(&sk, 32, b"Tests");
+ produces_same_hash(&sk, 64, b"Tests");
+ produces_same_hash(&sk, 28, b"Tests");
+
+ produces_same_hash(&sk, 1, b"");
+ produces_same_hash(&sk, 32, b"");
+ produces_same_hash(&sk, 64, b"");
+ produces_same_hash(&sk, 28, b"");
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_same_hash_different_usage(data: Vec<u8>, size: usize) -> bool {
+ use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
+
+ if (1..=BLAKE2B_OUTSIZE).contains(&size) {
+ // Will panic on incorrect results.
+ let sk = SecretKey::generate();
+ produces_same_hash(&sk, size, &data[..]);
+ }
+
+ true
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_same_state_different_usage(data: Vec<u8>, size: usize) -> bool {
+ use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_OUTSIZE;
+
+ if (1..=BLAKE2B_OUTSIZE).contains(&size) {
+ // Will panic on incorrect results.
+ let sk = SecretKey::generate();
+ produces_same_state(&sk, size, &data[..]);
+ }
+
+ true
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/mac/hmac.rs b/vendor/orion/src/hazardous/mac/hmac.rs
new file mode 100644
index 0000000..f5fecf2
--- /dev/null
+++ b/vendor/orion/src/hazardous/mac/hmac.rs
@@ -0,0 +1,919 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `secret_key`: The authentication key.
+//! - `data`: Data to be authenticated.
+//! - `expected`: The expected authentication tag.
+//!
+//! # 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.
+//! - The HMAC does not match the expected when verifying.
+//!
+//! # Security:
+//! - The secret key should always be generated using a CSPRNG.
+//! [`SecretKey::generate()`] can be used for this.
+//! - The minimum recommended size for a secret key is 64 bytes.
+//!
+//! # Recommendation:
+//! - If you are unsure of whether to use HMAC or Poly1305, it is most often
+//! easier to just use HMAC. See also [Cryptographic Right Answers].
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::mac::hmac::sha512::{HmacSha512, SecretKey};
+//!
+//! let key = SecretKey::generate();
+//!
+//! let mut state = HmacSha512::new(&key);
+//! state.update(b"Some message.")?;
+//! let tag = state.finalize()?;
+//!
+//! assert!(HmacSha512::verify(&tag, &key, b"Some message.").is_ok());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: hmac::sha512::HmacSha512::update
+//! [`reset()`]: hmac::sha512::HmacSha512::reset
+//! [`finalize()`]: hmac::sha512::HmacSha512::finalize
+//! [`SecretKey::generate()`]: hmac::sha512::SecretKey::generate
+//! [Cryptographic Right Answers]: https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html
+
+use crate::errors::UnknownCryptoError;
+use zeroize::Zeroize;
+
+/// A trait used to define a cryptographic hash function used by HMAC.
+pub(crate) trait HmacHashFunction: Clone {
+ /// The blocksize of the hash function.
+ const _BLOCKSIZE: usize;
+
+ /// The output size of the hash function.
+ const _OUTSIZE: usize;
+
+ /// Create a new instance of the hash function.
+ fn _new() -> Self;
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Finalize the hash and put the final digest into `dest`.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Compute a digest of `data` and copy it into `dest`.
+ fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError>;
+
+ #[cfg(test)]
+ /// Compare two Sha2 state objects to check if their fields
+ /// are the same.
+ fn compare_state_to_other(&self, other: &Self);
+}
+
+/// A trait used to define a HMAC function.
+pub(crate) trait HmacFunction {
+ // NOTE: Clippy complains this is not used, however it is used in both HKDF and PBKDF2. Perhaps a bug
+ // with min_const_generics?
+ #[allow(dead_code)]
+ /// The output size of the internal hash function used.
+ const HASH_FUNC_OUTSIZE: usize;
+
+ /// Create a new instance of the HMAC function, using a `secret_key` that may or may not be padded.
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError>
+ where
+ Self: Sized;
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Finalize the MAC and put the final tag into `dest`.
+ ///
+ /// NOTE: `dest` may be less than the complete output size of the hash function
+ /// (Self::HASH_FUNC_OUTSIZE). If that is the case, `dest.len()` bytes will be copied,
+ /// but `dest` should NEVER be empty.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Reset the state.
+ fn _reset(&mut self);
+}
+
+const IPAD: u8 = 0x36;
+const OPAD: u8 = 0x5C;
+
+#[derive(Clone)]
+pub(crate) struct Hmac<S: HmacHashFunction, const BLOCKSIZE: usize> {
+ working_hasher: S,
+ opad_hasher: S,
+ ipad_hasher: S,
+ is_finalized: bool,
+}
+
+impl<S: HmacHashFunction, const BLOCKSIZE: usize> core::fmt::Debug for Hmac<S, BLOCKSIZE> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "Hmac {{ working_hasher: [***OMITTED***], opad_hasher: [***OMITTED***], ipad_hasher: [***OMITTED***], is_finalized: {:?} }}",
+ self.is_finalized
+ )
+ }
+}
+
+impl<S: HmacHashFunction, const BLOCKSIZE: usize> Hmac<S, BLOCKSIZE> {
+ // NOTE: Clippy complains this is not used, however it is used in both HKDF and PBKDF2. Perhaps a bug
+ // with min_const_generics?
+ #[allow(dead_code)]
+ const HASH_FUNC_OUTSIZE: usize = S::_OUTSIZE;
+
+ /// Construct a state from a `secret_key`. The `secret_key` may be pre-padded or not.
+ ///
+ /// Ref: https://brycx.github.io/2018/08/06/hmac-and-precomputation-optimization.html
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ debug_assert_eq!(S::_BLOCKSIZE, BLOCKSIZE);
+ let mut ipad = [IPAD; BLOCKSIZE];
+
+ if secret_key.len() > BLOCKSIZE {
+ // SK is NOT pre-padded.
+ debug_assert!(BLOCKSIZE > S::_OUTSIZE);
+ S::_digest(secret_key, &mut ipad[..S::_OUTSIZE])?;
+ for elem in ipad.iter_mut().take(S::_OUTSIZE) {
+ *elem ^= IPAD;
+ }
+ } else {
+ // SK has been pre-padded or SK.len() <= BLOCKSIZE.
+ // Because 0x00 xor IPAD = IPAD, the existence of padding bytes (0x00)
+ // within SK, during this operation, is inconsequential.
+ xor_slices!(secret_key, &mut ipad);
+ }
+
+ let mut ih = S::_new();
+ ih._update(&ipad)?;
+
+ // Transform ipad into OPAD xor SK
+ for elem in ipad.iter_mut() {
+ *elem ^= IPAD ^ OPAD;
+ }
+
+ let mut oh = S::_new();
+ oh._update(&ipad)?;
+
+ ipad.iter_mut().zeroize();
+
+ Ok(Self {
+ working_hasher: ih.clone(),
+ opad_hasher: oh,
+ ipad_hasher: ih,
+ is_finalized: false,
+ })
+ }
+
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ if self.is_finalized {
+ Err(UnknownCryptoError)
+ } else {
+ self.working_hasher._update(data)
+ }
+ }
+
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ debug_assert!(!dest.is_empty());
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+
+ self.is_finalized = true;
+ let mut outer_hasher = self.opad_hasher.clone();
+ self.working_hasher._finalize(dest)?;
+ outer_hasher._update(dest)?;
+ outer_hasher._finalize(dest)
+ }
+
+ fn _reset(&mut self) {
+ self.working_hasher = self.ipad_hasher.clone();
+ self.is_finalized = false;
+ }
+
+ #[cfg(test)]
+ /// Compare two Hmac state objects to check if their fields
+ /// are the same.
+ pub(crate) fn compare_state_to_other(&self, other: &Self) {
+ self.working_hasher
+ .compare_state_to_other(&other.working_hasher);
+ self.opad_hasher.compare_state_to_other(&other.opad_hasher);
+ self.ipad_hasher.compare_state_to_other(&other.ipad_hasher);
+ assert_eq!(self.is_finalized, other.is_finalized);
+ }
+}
+
+/// HMAC-SHA256 (Hash-based Message Authentication Code) as specified in the [RFC 2104](https://tools.ietf.org/html/rfc2104).
+pub mod sha256 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha256::{self, Sha256};
+
+ construct_hmac_key! {
+ /// A type to represent the `SecretKey` that HMAC uses for authentication.
+ ///
+ /// # Note:
+ /// `SecretKey` pads the secret key for use with HMAC to a length of 64, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the secret key with padding.
+ ///
+ /// `len()` will return the length with padding (always 64).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, Sha256, sha256::SHA256_OUTSIZE, test_hmac_key, sha256::SHA256_BLOCKSIZE)
+ }
+
+ construct_tag! {
+ /// A type to represent the `Tag` that HMAC returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ (Tag, test_tag, sha256::SHA256_OUTSIZE, sha256::SHA256_OUTSIZE)
+ }
+
+ impl_from_trait!(Tag, sha256::SHA256_OUTSIZE);
+
+ use super::Hmac;
+
+ #[derive(Clone, Debug)]
+ /// HMAC-SHA256 streaming state.
+ pub struct HmacSha256 {
+ _state: Hmac<Sha256, { sha256::SHA256_BLOCKSIZE }>,
+ }
+
+ impl HmacSha256 {
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ _state: Hmac::<Sha256, { sha256::SHA256_BLOCKSIZE }>::_new(secret_key)?,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize `HmacSha256` struct with a given key.
+ pub fn new(secret_key: &SecretKey) -> Self {
+ // NOTE: `secret_key` has been pre-padded so .unwrap() is OK.
+ Self::_new(secret_key.unprotected_as_bytes()).unwrap()
+ }
+
+ /// 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)
+ }
+
+ /// Return a HMAC-SHA256 tag.
+ 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 HMAC-SHA256 tag.
+ pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ let mut dest = [0u8; sha256::SHA256_OUTSIZE];
+ self._finalize_internal(&mut dest)?;
+
+ Ok(Tag::from(dest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// One-shot function for generating an HMAC-SHA256 tag of `data`.
+ pub fn hmac(secret_key: &SecretKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ let mut ctx = Self::new(secret_key);
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify a HMAC-SHA256 tag in constant time.
+ pub fn verify(
+ expected: &Tag,
+ secret_key: &SecretKey,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ if &Self::hmac(secret_key, data)? == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+ }
+
+ impl HmacFunction for HmacSha256 {
+ /// The output size of the internal hash function used.
+ const HASH_FUNC_OUTSIZE: usize = sha256::SHA256_OUTSIZE;
+
+ /// Create a new instance of the HMAC function, using a `secret_key` that may or may not be padded.
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Self::_new(secret_key)
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the MAC and put the final tag into `dest`.
+ ///
+ /// NOTE: `dest` may be less than the complete output size of the hash function
+ /// (Self::HASH_FUNC_OUTSIZE). If that is the case, `dest.len()` bytes will be copied,
+ /// but `dest` should NEVER be empty.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ /// Reset the state.
+ fn _reset(&mut self) {
+ self._state._reset()
+ }
+ }
+
+ #[cfg(test)]
+ mod public {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let secret_key = SecretKey::generate();
+ let initial_state = HmacSha256::new(&secret_key);
+ let debug = format!("{:?}", initial_state);
+ let expected = "HmacSha256 { _state: Hmac { working_hasher: [***OMITTED***], opad_hasher: [***OMITTED***], ipad_hasher: [***OMITTED***], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different key, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
+ let sk = SecretKey::generate();
+ let mut state = HmacSha256::new(&sk);
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+ let bad_sk = SecretKey::generate();
+
+ HmacSha256::verify(&tag, &bad_sk, &data[..]).is_err()
+ }
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ const KEY: [u8; 32] = [0u8; 32];
+
+ impl TestableStreamingContext<Tag> for HmacSha256 {
+ 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<Tag, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ HmacSha256::hmac(&SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ // This will only run verification tests on differing input. They do not
+ // include tests for different secret keys.
+ HmacSha256::verify(expected, &SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn compare_states(state_1: &HmacSha256, state_2: &HmacSha256) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state = HmacSha256::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha256>::new(
+ initial_state,
+ sha256::SHA256_BLOCKSIZE,
+ );
+ 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 = HmacSha256::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha256>::new(
+ initial_state,
+ sha256::SHA256_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+ }
+}
+
+/// HMAC-SHA384 (Hash-based Message Authentication Code) as specified in the [RFC 2104](https://tools.ietf.org/html/rfc2104).
+pub mod sha384 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha384::{self, Sha384};
+
+ construct_hmac_key! {
+ /// A type to represent the `SecretKey` that HMAC uses for authentication.
+ ///
+ /// # Note:
+ /// `SecretKey` pads the secret key for use with HMAC to a length of 128, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the secret key with padding.
+ ///
+ /// `len()` will return the length with padding (always 128).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, Sha384, sha384::SHA384_OUTSIZE, test_hmac_key, sha384::SHA384_BLOCKSIZE)
+ }
+
+ construct_tag! {
+ /// A type to represent the `Tag` that HMAC returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 48 bytes.
+ (Tag, test_tag, sha384::SHA384_OUTSIZE, sha384::SHA384_OUTSIZE)
+ }
+
+ impl_from_trait!(Tag, sha384::SHA384_OUTSIZE);
+
+ use super::Hmac;
+
+ #[derive(Clone, Debug)]
+ /// HMAC-SHA384 streaming state.
+ pub struct HmacSha384 {
+ _state: Hmac<Sha384, { sha384::SHA384_BLOCKSIZE }>,
+ }
+
+ impl HmacSha384 {
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ _state: Hmac::<Sha384, { sha384::SHA384_BLOCKSIZE }>::_new(secret_key)?,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize `HmacSha384` struct with a given key.
+ pub fn new(secret_key: &SecretKey) -> Self {
+ // NOTE: `secret_key` has been pre-padded so .unwrap() is OK.
+ Self::_new(secret_key.unprotected_as_bytes()).unwrap()
+ }
+
+ /// 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)
+ }
+
+ /// Return a HMAC-SHA384 tag.
+ 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 HMAC-SHA384 tag.
+ pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ let mut dest = [0u8; sha384::SHA384_OUTSIZE];
+ self._finalize_internal(&mut dest)?;
+
+ Ok(Tag::from(dest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// One-shot function for generating an HMAC-SHA384 tag of `data`.
+ pub fn hmac(secret_key: &SecretKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ let mut ctx = Self::new(secret_key);
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify a HMAC-SHA384 tag in constant time.
+ pub fn verify(
+ expected: &Tag,
+ secret_key: &SecretKey,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ if &Self::hmac(secret_key, data)? == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+ }
+
+ impl HmacFunction for HmacSha384 {
+ /// The output size of the internal hash function used.
+ const HASH_FUNC_OUTSIZE: usize = sha384::SHA384_OUTSIZE;
+
+ /// Create a new instance of the HMAC function, using a `secret_key` that may or may not be padded.
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Self::_new(secret_key)
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the MAC and put the final tag into `dest`.
+ ///
+ /// NOTE: `dest` may be less than the complete output size of the hash function
+ /// (Self::HASH_FUNC_OUTSIZE). If that is the case, `dest.len()` bytes will be copied,
+ /// but `dest` should NEVER be empty.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ /// Reset the state.
+ fn _reset(&mut self) {
+ self._state._reset()
+ }
+ }
+
+ #[cfg(test)]
+ mod public {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let secret_key = SecretKey::generate();
+ let initial_state = HmacSha384::new(&secret_key);
+ let debug = format!("{:?}", initial_state);
+ let expected = "HmacSha384 { _state: Hmac { working_hasher: [***OMITTED***], opad_hasher: [***OMITTED***], ipad_hasher: [***OMITTED***], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different key, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
+ let sk = SecretKey::generate();
+ let mut state = HmacSha384::new(&sk);
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+ let bad_sk = SecretKey::generate();
+
+ HmacSha384::verify(&tag, &bad_sk, &data[..]).is_err()
+ }
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ const KEY: [u8; 32] = [0u8; 32];
+
+ impl TestableStreamingContext<Tag> for HmacSha384 {
+ 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<Tag, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ HmacSha384::hmac(&SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ // This will only run verification tests on differing input. They do not
+ // include tests for different secret keys.
+ HmacSha384::verify(expected, &SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn compare_states(state_1: &HmacSha384, state_2: &HmacSha384) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state = HmacSha384::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha384>::new(
+ initial_state,
+ sha384::SHA384_BLOCKSIZE,
+ );
+ 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 = HmacSha384::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha384>::new(
+ initial_state,
+ sha384::SHA384_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+ }
+}
+
+/// HMAC-SHA512 (Hash-based Message Authentication Code) as specified in the [RFC 2104](https://tools.ietf.org/html/rfc2104).
+pub mod sha512 {
+ use super::*;
+ use crate::hazardous::hash::sha2::sha512::{self, Sha512};
+
+ construct_hmac_key! {
+ /// A type to represent the `SecretKey` that HMAC uses for authentication.
+ ///
+ /// # Note:
+ /// `SecretKey` pads the secret key for use with HMAC to a length of 128, when initialized.
+ ///
+ /// Using `unprotected_as_bytes()` will return the secret key with padding.
+ ///
+ /// `len()` will return the length with padding (always 128).
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, Sha512, sha512::SHA512_OUTSIZE, test_hmac_key, sha512::SHA512_BLOCKSIZE)
+ }
+
+ construct_tag! {
+ /// A type to represent the `Tag` that HMAC returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 64 bytes.
+ (Tag, test_tag, sha512::SHA512_OUTSIZE, sha512::SHA512_OUTSIZE)
+ }
+
+ impl_from_trait!(Tag, sha512::SHA512_OUTSIZE);
+
+ use super::Hmac;
+
+ #[derive(Clone, Debug)]
+ /// HMAC-SHA512 streaming state.
+ pub struct HmacSha512 {
+ _state: Hmac<Sha512, { sha512::SHA512_BLOCKSIZE }>,
+ }
+
+ impl HmacSha512 {
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Ok(Self {
+ _state: Hmac::<Sha512, { sha512::SHA512_BLOCKSIZE }>::_new(secret_key)?,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize `HmacSha512` struct with a given key.
+ pub fn new(secret_key: &SecretKey) -> Self {
+ // NOTE: `secret_key` has been pre-padded so .unwrap() is OK.
+ Self::_new(secret_key.unprotected_as_bytes()).unwrap()
+ }
+
+ /// 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)
+ }
+
+ /// Return a HMAC-SHA512 tag.
+ 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 HMAC-SHA512 tag.
+ pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ let mut dest = [0u8; sha512::SHA512_OUTSIZE];
+ self._finalize_internal(&mut dest)?;
+
+ Ok(Tag::from(dest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// One-shot function for generating an HMAC-SHA512 tag of `data`.
+ pub fn hmac(secret_key: &SecretKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ let mut ctx = Self::new(secret_key);
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify a HMAC-SHA512 tag in constant time.
+ pub fn verify(
+ expected: &Tag,
+ secret_key: &SecretKey,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ if &Self::hmac(secret_key, data)? == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+ }
+
+ impl HmacFunction for HmacSha512 {
+ /// The output size of the internal hash function used.
+ const HASH_FUNC_OUTSIZE: usize = sha512::SHA512_OUTSIZE;
+
+ /// Create a new instance of the HMAC function, using a `secret_key` that may or may not be padded.
+ fn _new(secret_key: &[u8]) -> Result<Self, UnknownCryptoError> {
+ Self::_new(secret_key)
+ }
+
+ /// Update the internal state with `data`.
+ fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the MAC and put the final tag into `dest`.
+ ///
+ /// NOTE: `dest` may be less than the complete output size of the hash function
+ /// (Self::HASH_FUNC_OUTSIZE). If that is the case, `dest.len()` bytes will be copied,
+ /// but `dest` should NEVER be empty.
+ fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ /// Reset the state.
+ fn _reset(&mut self) {
+ self._state._reset()
+ }
+ }
+
+ #[cfg(test)]
+ mod public {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let secret_key = SecretKey::generate();
+ let initial_state = HmacSha512::new(&secret_key);
+ let debug = format!("{:?}", initial_state);
+ let expected = "HmacSha512 { _state: Hmac { working_hasher: [***OMITTED***], opad_hasher: [***OMITTED***], ipad_hasher: [***OMITTED***], is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different key, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
+ let sk = SecretKey::generate();
+ let mut state = HmacSha512::new(&sk);
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+ let bad_sk = SecretKey::generate();
+
+ HmacSha512::verify(&tag, &bad_sk, &data[..]).is_err()
+ }
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ const KEY: [u8; 32] = [0u8; 32];
+
+ impl TestableStreamingContext<Tag> for HmacSha512 {
+ 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<Tag, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ HmacSha512::hmac(&SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ // This will only run verification tests on differing input. They do not
+ // include tests for different secret keys.
+ HmacSha512::verify(expected, &SecretKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn compare_states(state_1: &HmacSha512, state_2: &HmacSha512) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state = HmacSha512::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha512>::new(
+ initial_state,
+ sha512::SHA512_BLOCKSIZE,
+ );
+ 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 = HmacSha512::new(&SecretKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, HmacSha512>::new(
+ initial_state,
+ sha512::SHA512_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/mac/mod.rs b/vendor/orion/src/hazardous/mac/mod.rs
new file mode 100644
index 0000000..114062b
--- /dev/null
+++ b/vendor/orion/src/hazardous/mac/mod.rs
@@ -0,0 +1,30 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// HMAC (Hash-based Message Authentication Code) as specified in the [RFC 2104](https://tools.ietf.org/html/rfc2104).
+pub mod hmac;
+
+/// Poly1305 as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub mod poly1305;
+
+/// BLAKE2b as specified in the [RFC 7693](https://tools.ietf.org/html/rfc7693).
+pub mod blake2b;
diff --git a/vendor/orion/src/hazardous/mac/poly1305.rs b/vendor/orion/src/hazardous/mac/poly1305.rs
new file mode 100644
index 0000000..b9c974d
--- /dev/null
+++ b/vendor/orion/src/hazardous/mac/poly1305.rs
@@ -0,0 +1,573 @@
+// MIT License
+
+// Copyright (c) 2018-2023 The orion Developers
+// Based on the algorithm from https://github.com/floodyberry/poly1305-donna
+
+// 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 implementation is based on [poly1305-donna] by Andrew Moon.
+//!
+//! # Parameters:
+//! - `data`: Data to be authenticated.
+//! - `one_time_key`: One-time key used to authenticate.
+//! - `expected`: The expected tag that needs to be verified.
+//!
+//! # 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.
+//! - The calculated tag does not match the expected when verifying.
+//!
+//! # Security:
+//! - A given key must never be used more than once. A unique [`OneTimeKey`],
+//! for each message authenticated, is required. If a key is used more than once,
+//! it reveals enough information for an attacker to forge future authentications with the same key.
+//! - The one-time key should be generated using a CSPRNG.
+//! [`OneTimeKey::generate()`] can be used for this.
+//!
+//! # Recommendation:
+//! - If you are unsure of whether to use HMAC or Poly1305, it is most often
+//! easier to just use HMAC. See also [Cryptographic Right Answers].
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::mac::poly1305::{OneTimeKey, Poly1305};
+//!
+//! let one_time_key = OneTimeKey::generate();
+//! let msg = "Some message.";
+//!
+//! let mut poly1305_state = Poly1305::new(&one_time_key);
+//! poly1305_state.update(msg.as_bytes())?;
+//! let tag = poly1305_state.finalize()?;
+//!
+//! assert!(Poly1305::verify(&tag, &one_time_key, msg.as_bytes()).is_ok());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: poly1305::Poly1305::update
+//! [`reset()`]: poly1305::Poly1305::reset
+//! [`finalize()`]: poly1305::Poly1305::finalize
+//! [`OneTimeKey::generate()`]: poly1305::OneTimeKey::generate
+//! [`OneTimeKey`]: poly1305::OneTimeKey
+//! [poly1305-donna]: https://github.com/floodyberry/poly1305-donna
+//! [Cryptographic Right Answers]: https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html
+
+use crate::{
+ errors::UnknownCryptoError,
+ util::endianness::{load_u32_le, store_u32_into_le},
+};
+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_relax, fiat_poly1305_selectznz,
+ fiat_poly1305_subborrowx_u26, fiat_poly1305_tight_field_element, fiat_poly1305_u1,
+};
+
+/// The blocksize which Poly1305 operates on.
+const POLY1305_BLOCKSIZE: usize = 16;
+/// The output size for Poly1305.
+pub const POLY1305_OUTSIZE: usize = 16;
+/// The key size for Poly1305.
+pub const POLY1305_KEYSIZE: usize = 32;
+/// Type for a Poly1305 tag.
+type Poly1305Tag = [u8; POLY1305_OUTSIZE];
+
+construct_secret_key! {
+ /// A type to represent the `OneTimeKey` that Poly1305 uses for authentication.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (OneTimeKey, test_one_time_key, POLY1305_KEYSIZE, POLY1305_KEYSIZE, POLY1305_KEYSIZE)
+}
+
+impl_from_trait!(OneTimeKey, POLY1305_KEYSIZE);
+
+construct_tag! {
+ /// A type to represent the `Tag` that Poly1305 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 16 bytes.
+ (Tag, test_tag, POLY1305_OUTSIZE, POLY1305_OUTSIZE)
+}
+
+impl_from_trait!(Tag, POLY1305_OUTSIZE);
+
+#[derive(Clone)]
+/// Poly1305 streaming state.
+pub struct Poly1305 {
+ a: fiat_poly1305_tight_field_element,
+ r: fiat_poly1305_loose_field_element,
+ s: [u32; 4],
+ leftover: usize,
+ buffer: [u8; POLY1305_BLOCKSIZE],
+ is_finalized: bool,
+}
+
+impl Drop for Poly1305 {
+ fn drop(&mut self) {
+ use zeroize::Zeroize;
+ self.a.0.zeroize();
+ self.r.0.zeroize();
+ self.s.zeroize();
+ self.buffer.zeroize();
+ }
+}
+
+impl core::fmt::Debug for Poly1305 {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "Poly1305 {{ a: [***OMITTED***], r: [***OMITTED***], s: [***OMITTED***], leftover: [***OMITTED***], buffer: [***OMITTED***], is_finalized: {:?} }}",
+ self.is_finalized
+ )
+ }
+}
+
+impl Poly1305 {
+ /// Prime 2^130-5 in little-endian.
+ const PRIME: [u8; 17] = [
+ 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3,
+ ];
+
+ /// Process a datablock of `POLY1305_BLOCKSIZE` length.
+ fn process_block(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ if data.len() != POLY1305_BLOCKSIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut mb = [0u8; 17];
+ mb[..16].copy_from_slice(data);
+ // 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]);
+ fiat_poly1305_from_bytes(&mut m, &mb);
+
+ // h += m
+ 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);
+
+ Ok(())
+ }
+
+ #[rustfmt::skip]
+ #[allow(clippy::identity_op)]
+ /// 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]);
+ 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]);
+ fiat_poly1305_from_bytes(&mut p, &Self::PRIME);
+
+ let mut carry: fiat_poly1305_u1 = 0;
+ let mut g0: u32 = 0; let c = carry; fiat_poly1305_subborrowx_u26(&mut g0, &mut carry, c, buf_h[0], p[0]);
+ let mut g1: u32 = 0; let c = carry; fiat_poly1305_subborrowx_u26(&mut g1, &mut carry, c, buf_h[1], p[1]);
+ let mut g2: u32 = 0; let c = carry; fiat_poly1305_subborrowx_u26(&mut g2, &mut carry, c, buf_h[2], p[2]);
+ let mut g3: u32 = 0; let c = carry; fiat_poly1305_subborrowx_u26(&mut g3, &mut carry, c, buf_h[3], p[3]);
+ let mut g4: u32 = 0; let c = carry; fiat_poly1305_subborrowx_u26(&mut g4, &mut carry, c, buf_h[4], p[4]);
+
+ // 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.0);
+
+ let mut h0 = ret[0];
+ let mut h1 = ret[1];
+ let mut h2 = ret[2];
+ let mut h3 = ret[3];
+ let h4 = ret[4];
+
+ // h = h % (2^128)
+ h0 = ((h0) | (h1 << 26)) & 0xffffffff;
+ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+ // mac = (h + pad) % (2^128)
+ let mut f: u64 = (h0 as u64) + (self.s[0] as u64); h0 = f as u32;
+ f = (h1 as u64) + (self.s[1] as u64) + (f >> 32); h1 = f as u32;
+ f = (h2 as u64) + (self.s[2] as u64) + (f >> 32); h2 = f as u32;
+ f = (h3 as u64) + (self.s[3] as u64) + (f >> 32); h3 = f as u32;
+
+ // Set self.a to MAC result
+ self.a[0] = h0;
+ self.a[1] = h1;
+ self.a[2] = h2;
+ self.a[3] = h3;
+ }
+
+ #[allow(clippy::unreadable_literal)]
+ /// Initialize a `Poly1305` struct with a given one-time key.
+ pub fn new(one_time_key: &OneTimeKey) -> Self {
+ let mut state = Self {
+ 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],
+ is_finalized: false,
+ };
+
+ state.r[0] = (load_u32_le(&one_time_key.unprotected_as_bytes()[0..4])) & 0x3ffffff;
+ state.r[1] = (load_u32_le(&one_time_key.unprotected_as_bytes()[3..7]) >> 2) & 0x3ffff03;
+ state.r[2] = (load_u32_le(&one_time_key.unprotected_as_bytes()[6..10]) >> 4) & 0x3ffc0ff;
+ state.r[3] = (load_u32_le(&one_time_key.unprotected_as_bytes()[9..13]) >> 6) & 0x3f03fff;
+ state.r[4] = (load_u32_le(&one_time_key.unprotected_as_bytes()[12..16]) >> 8) & 0x00fffff;
+
+ state.s[0] = load_u32_le(&one_time_key.unprotected_as_bytes()[16..20]);
+ state.s[1] = load_u32_le(&one_time_key.unprotected_as_bytes()[20..24]);
+ state.s[2] = load_u32_le(&one_time_key.unprotected_as_bytes()[24..28]);
+ state.s[3] = load_u32_le(&one_time_key.unprotected_as_bytes()[28..32]);
+
+ state
+ }
+
+ /// Update state with a `data` and pad it to blocksize with 0, if not
+ /// evenly divisible by blocksize.
+ pub(crate) fn process_pad_to_blocksize(
+ &mut self,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+ if data.is_empty() {
+ return Ok(());
+ }
+
+ let mut blocksize_iter = data.chunks_exact(POLY1305_BLOCKSIZE);
+ for block in &mut blocksize_iter {
+ self.process_block(block).unwrap();
+ }
+
+ let remaining = blocksize_iter.remainder();
+ if !remaining.is_empty() {
+ let mut pad = [0u8; POLY1305_BLOCKSIZE];
+ pad[..remaining.len()].copy_from_slice(remaining);
+ self.process_block(&pad).unwrap();
+ }
+
+ Ok(())
+ }
+
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) {
+ self.a = fiat_poly1305_tight_field_element([0u32; 5]);
+ self.leftover = 0;
+ self.is_finalized = false;
+ self.buffer = [0u8; POLY1305_BLOCKSIZE];
+ }
+
+ #[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> {
+ 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 <= POLY1305_BLOCKSIZE);
+
+ let mut want = POLY1305_BLOCKSIZE - 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 < POLY1305_BLOCKSIZE {
+ return Ok(());
+ }
+
+ let tmp = self.buffer;
+ self.process_block(&tmp)?;
+ self.leftover = 0;
+ }
+
+ while bytes.len() >= POLY1305_BLOCKSIZE {
+ self.process_block(&bytes[0..POLY1305_BLOCKSIZE])?;
+ bytes = &bytes[POLY1305_BLOCKSIZE..];
+ }
+
+ self.buffer[..bytes.len()].copy_from_slice(bytes);
+ self.leftover = bytes.len();
+
+ Ok(())
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a Poly1305 tag.
+ pub fn finalize(&mut self) -> Result<Tag, UnknownCryptoError> {
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+
+ self.is_finalized = true;
+
+ let mut local_buffer: Poly1305Tag = self.buffer;
+
+ if self.leftover != 0 {
+ local_buffer[self.leftover] = 1;
+ // Pad the last block with zeroes before processing it
+ for buf_itm in local_buffer
+ .iter_mut()
+ .take(POLY1305_BLOCKSIZE)
+ .skip(self.leftover + 1)
+ {
+ *buf_itm = 0u8;
+ }
+
+ self.process_block(&local_buffer)?;
+ }
+
+ self.process_end_of_stream();
+ store_u32_into_le(&self.a.0[0..4], &mut local_buffer);
+
+ Ok(Tag::from(local_buffer))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// One-shot function for generating a Poly1305 tag of `data`.
+ pub fn poly1305(one_time_key: &OneTimeKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ let mut poly_1305_state = Self::new(one_time_key);
+ poly_1305_state.update(data)?;
+ poly_1305_state.finalize()
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Verify a Poly1305 tag in constant time.
+ pub fn verify(
+ expected: &Tag,
+ one_time_key: &OneTimeKey,
+ data: &[u8],
+ ) -> Result<(), UnknownCryptoError> {
+ if &Self::poly1305(one_time_key, data)? == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let secret_key = OneTimeKey::generate();
+ let initial_state = Poly1305::new(&secret_key);
+ let debug = format!("{:?}", initial_state);
+ let expected = "Poly1305 { a: [***OMITTED***], r: [***OMITTED***], s: [***OMITTED***], leftover: [***OMITTED***], buffer: [***OMITTED***], is_finalized: false }";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_verify {
+ use super::*;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// When using a different key, verify() should always yield an error.
+ /// NOTE: Using different and same input data is tested with TestableStreamingContext.
+ fn prop_verify_diff_key_false(data: Vec<u8>) -> bool {
+ let sk = OneTimeKey::generate();
+ let mut state = Poly1305::new(&sk);
+ state.update(&data[..]).unwrap();
+ let tag = state.finalize().unwrap();
+ let bad_sk = OneTimeKey::generate();
+
+ Poly1305::verify(&tag, &bad_sk, &data[..]).is_err()
+ }
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::{
+ StreamingContextConsistencyTester, TestableStreamingContext,
+ };
+
+ // If a Poly1305 one-time key is all 0's then the tag will also be, regardless
+ // of which message data has been processed.
+ const KEY: [u8; 32] = [24u8; 32];
+
+ impl TestableStreamingContext<Tag> for Poly1305 {
+ 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<Tag, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ Poly1305::poly1305(&OneTimeKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn verify_result(expected: &Tag, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ // This will only run verification tests on differing input. They do not
+ // include tests for different secret keys.
+ Poly1305::verify(expected, &OneTimeKey::from_slice(&KEY).unwrap(), input)
+ }
+
+ fn compare_states(state_1: &Poly1305, state_2: &Poly1305) {
+ 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[..]);
+ assert_eq!(state_1.is_finalized, state_2.is_finalized);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Poly1305 = Poly1305::new(&OneTimeKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, Poly1305>::new(
+ initial_state,
+ POLY1305_BLOCKSIZE,
+ );
+ 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: Poly1305 = Poly1305::new(&OneTimeKey::from_slice(&KEY).unwrap());
+
+ let test_runner = StreamingContextConsistencyTester::<Tag, Poly1305>::new(
+ initial_state,
+ POLY1305_BLOCKSIZE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_process_pad_to_blocksize {
+ use super::*;
+
+ #[test]
+ fn test_process_err_on_finalized() {
+ let sk = OneTimeKey::from_slice(&[0u8; 32]).unwrap();
+ let mut state = Poly1305::new(&sk);
+
+ state.process_pad_to_blocksize(&[0u8; 16]).unwrap();
+ let _ = state.finalize().unwrap();
+ assert!(state.process_pad_to_blocksize(&[0u8; 16]).is_err());
+ }
+
+ #[test]
+ fn test_process_pad_no_pad() {
+ let sk = OneTimeKey::from_slice(&[0u8; 32]).unwrap();
+ let mut state_pad = Poly1305::new(&sk);
+ let mut state_no_pad = Poly1305::new(&sk);
+
+ // 15 missing to be evenly divisible by 16.
+ state_pad.process_pad_to_blocksize(&[0u8; 17]).unwrap();
+ state_no_pad.process_pad_to_blocksize(&[0u8; 32]).unwrap();
+
+ assert_eq!(
+ state_no_pad.finalize().unwrap(),
+ state_pad.finalize().unwrap()
+ );
+ }
+ }
+
+ mod test_process_block {
+ use super::*;
+
+ #[test]
+ fn test_process_block_len() {
+ let block_0 = [0u8; 0];
+ let block_1 = [0u8; 15];
+ let block_2 = [0u8; 17];
+ let block_3 = [0u8; 16];
+
+ let sk = OneTimeKey::from_slice(&[0u8; 32]).unwrap();
+ let mut state = Poly1305::new(&sk);
+
+ assert!(state.process_block(&block_0).is_err());
+ assert!(state.process_block(&block_1).is_err());
+ assert!(state.process_block(&block_2).is_err());
+ assert!(state.process_block(&block_3).is_ok());
+ }
+ }
+
+ mod test_process_end_of_stream {
+ use super::*;
+
+ #[test]
+ fn test_process_no_panic() {
+ let block = [0u8; 16];
+ let sk = OneTimeKey::from_slice(&[0u8; 32]).unwrap();
+ let mut state = Poly1305::new(&sk);
+ // Should not panic
+ state.process_end_of_stream();
+ state.reset();
+ state.process_end_of_stream();
+
+ let mut state = Poly1305::new(&sk);
+ state.process_block(&block).unwrap();
+ // Should not panic
+ state.process_end_of_stream();
+ state.reset();
+ state.process_end_of_stream();
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/mod.rs b/vendor/orion/src/hazardous/mod.rs
new file mode 100644
index 0000000..ff8c188
--- /dev/null
+++ b/vendor/orion/src/hazardous/mod.rs
@@ -0,0 +1,53 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+//! ### **Caution**:
+//! Usage of the `hazardous` module is __**only intended for advanced users**__.
+//! `hazardous` contains implementations with a much higher degree of control.
+//! It is also much easier to misuse those implementations. Only use `hazardous`
+//! if absolutely necessary.
+
+/// AEADs (Authenticated Encryption with Associated Data).
+pub mod aead;
+
+/// Cryptographic hash functions.
+pub mod hash;
+
+/// MACs (Message Authentication Code).
+pub mod mac;
+
+/// KDFs (Key Derivation Function) and PBKDFs (Password-Based Key Derivation
+/// Function).
+pub mod kdf;
+
+/// Stream ciphers.
+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;
diff --git a/vendor/orion/src/hazardous/stream/chacha20.rs b/vendor/orion/src/hazardous/stream/chacha20.rs
new file mode 100644
index 0000000..f5c9bcd
--- /dev/null
+++ b/vendor/orion/src/hazardous/stream/chacha20.rs
@@ -0,0 +1,1331 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `secret_key`: The secret key.
+//! - `nonce`: The nonce value.
+//! - `initial_counter`: The initial counter value. In most cases, this is `0`.
+//! - `ciphertext`: The encrypted data.
+//! - `plaintext`: The data to be encrypted.
+//! - `dst_out`: Destination array that will hold the ciphertext/plaintext after
+//! encryption/decryption.
+//!
+//! `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` or `ciphertext`.
+//! - `plaintext` or `ciphertext` is empty.
+//! - The `initial_counter` is high enough to cause a potential overflow.
+//!
+//! Even though `dst_out` is allowed to be of greater length than `plaintext`,
+//! the `ciphertext` produced by `chacha20`/`xchacha20` will always be of the
+//! same length as the `plaintext`.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than `2^32-1` keystream blocks are processed or 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.
+//! - Functions herein do not provide any data integrity. If you need
+//! data integrity, which is nearly ***always the case***, you should use an
+//! AEAD construction instead. See the [`aead`](super::aead) module for this.
+//! - Only a nonce for XChaCha20 is big enough to be randomly generated using a CSPRNG.
+//! - To securely generate a strong key, use [`SecretKey::generate()`].
+//!
+//! # Recommendation:
+//! - It is recommended to use [`XChaCha20Poly1305`] when possible.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::stream::chacha20;
+//!
+//! let secret_key = chacha20::SecretKey::generate();
+//!
+//! // WARNING: This nonce is only meant for demonstration and should not
+//! // be repeated. Please read the security section.
+//! let nonce = chacha20::Nonce::from([0u8; 12]);
+//! let message = "Data to protect".as_bytes();
+//!
+//! // The length of this message is 15.
+//!
+//! let mut dst_out_pt = [0u8; 15];
+//! let mut dst_out_ct = [0u8; 15];
+//!
+//! chacha20::encrypt(&secret_key, &nonce, 0, message, &mut dst_out_ct)?;
+//!
+//! chacha20::decrypt(&secret_key, &nonce, 0, &dst_out_ct, &mut dst_out_pt)?;
+//!
+//! assert_eq!(dst_out_pt, message);
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`SecretKey::generate()`]: chacha20::SecretKey::generate()
+//! [`XChaCha20Poly1305`]: super::aead::xchacha20poly1305
+//! [RFC]: https://tools.ietf.org/html/rfc8439
+use crate::errors::UnknownCryptoError;
+use crate::util::endianness::load_u32_le;
+use crate::util::u32x4::U32x4;
+use zeroize::{Zeroize, Zeroizing};
+
+/// The key size for ChaCha20.
+pub const CHACHA_KEYSIZE: usize = 32;
+/// The nonce size for IETF ChaCha20.
+pub const IETF_CHACHA_NONCESIZE: usize = 12;
+/// The blocksize which ChaCha20 operates on.
+pub(crate) const CHACHA_BLOCKSIZE: usize = 64;
+/// The size of the subkey that HChaCha20 returns.
+const HCHACHA_OUTSIZE: usize = 32;
+/// The nonce size for HChaCha20.
+pub(crate) const HCHACHA_NONCESIZE: usize = 16;
+
+construct_secret_key! {
+ /// A type to represent the `SecretKey` that Chacha20, XChaCha20, ChaCha20-Poly1305 and
+ /// XChaCha20-Poly1305 use.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, test_secret_key, CHACHA_KEYSIZE, CHACHA_KEYSIZE, CHACHA_KEYSIZE)
+}
+
+impl_from_trait!(SecretKey, CHACHA_KEYSIZE);
+
+construct_public! {
+ /// A type that represents a `Nonce` that ChaCha20 and ChaCha20-Poly1305 use.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 12 bytes.
+ (Nonce, test_nonce, IETF_CHACHA_NONCESIZE, IETF_CHACHA_NONCESIZE)
+}
+
+impl_from_trait!(Nonce, IETF_CHACHA_NONCESIZE);
+
+macro_rules! ROUND {
+ ($r0:expr, $r1:expr, $r2:expr, $r3:expr) => {
+ $r0 = $r0.wrapping_add($r1);
+ $r3 = ($r3 ^ $r0).rotate_left(16);
+
+ $r2 = $r2.wrapping_add($r3);
+ $r1 = ($r1 ^ $r2).rotate_left(12);
+
+ $r0 = $r0.wrapping_add($r1);
+ $r3 = ($r3 ^ $r0).rotate_left(8);
+
+ $r2 = $r2.wrapping_add($r3);
+ $r1 = ($r1 ^ $r2).rotate_left(7);
+ };
+}
+
+macro_rules! DOUBLE_ROUND {
+ ($r0:expr, $r1:expr, $r2:expr, $r3:expr) => {
+ ROUND!($r0, $r1, $r2, $r3);
+
+ // Shuffle
+ $r1 = $r1.shl_1();
+ $r2 = $r2.shl_2();
+ $r3 = $r3.shl_3();
+
+ ROUND!($r0, $r1, $r2, $r3);
+
+ // Unshuffle
+ $r1 = $r1.shl_3();
+ $r2 = $r2.shl_2();
+ $r3 = $r3.shl_1();
+ };
+}
+pub(crate) struct ChaCha20 {
+ state: [U32x4; 4],
+ internal_counter: u32,
+ is_ietf: bool,
+}
+
+impl Drop for ChaCha20 {
+ fn drop(&mut self) {
+ self.state.iter_mut().zeroize();
+ }
+}
+
+impl ChaCha20 {
+ #[allow(clippy::unreadable_literal)]
+ /// Initialize either a ChaCha or HChaCha state with a `secret_key` and
+ /// `nonce`.
+ pub(crate) fn new(sk: &[u8], n: &[u8], is_ietf: bool) -> Result<Self, UnknownCryptoError> {
+ debug_assert_eq!(sk.len(), CHACHA_KEYSIZE);
+ if (n.len() != IETF_CHACHA_NONCESIZE) && is_ietf {
+ return Err(UnknownCryptoError);
+ }
+ if (n.len() != HCHACHA_NONCESIZE) && !is_ietf {
+ return Err(UnknownCryptoError);
+ }
+
+ // Row 0 with constants.
+ let r0 = U32x4(0x61707865, 0x3320646e, 0x79622d32, 0x6b206574);
+
+ // Row 1 and 2 with secret key.
+ let r1 = U32x4(
+ load_u32_le(&sk[0..4]),
+ load_u32_le(&sk[4..8]),
+ load_u32_le(&sk[8..12]),
+ load_u32_le(&sk[12..16]),
+ );
+
+ let r2 = U32x4(
+ load_u32_le(&sk[16..20]),
+ load_u32_le(&sk[20..24]),
+ load_u32_le(&sk[24..28]),
+ load_u32_le(&sk[28..32]),
+ );
+
+ // Row 3 with counter and nonce if IETF,
+ // but only nonce if HChaCha20.
+ let r3 = if is_ietf {
+ U32x4(
+ 0, // Default counter
+ load_u32_le(&n[0..4]),
+ load_u32_le(&n[4..8]),
+ load_u32_le(&n[8..12]),
+ )
+ } else {
+ U32x4(
+ load_u32_le(&n[0..4]),
+ load_u32_le(&n[4..8]),
+ load_u32_le(&n[8..12]),
+ load_u32_le(&n[12..16]),
+ )
+ };
+
+ Ok(Self {
+ state: [r0, r1, r2, r3],
+ internal_counter: 0,
+ is_ietf,
+ })
+ }
+
+ /// Check that we can produce one more keystream block, given the current state.
+ ///
+ /// If the internal counter would overflow, we return an error.
+ pub(crate) fn next_produceable(&self) -> Result<(), UnknownCryptoError> {
+ if self.internal_counter.checked_add(1).is_none() {
+ Err(UnknownCryptoError)
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Process the next keystream and copy into destination array.
+ pub(crate) fn keystream_block(&mut self, block_counter: u32, inplace: &mut [u8]) {
+ debug_assert!(if self.is_ietf {
+ inplace.len() == CHACHA_BLOCKSIZE
+ } else {
+ inplace.len() == HCHACHA_OUTSIZE
+ });
+
+ if self.is_ietf {
+ self.state[3].0 = block_counter;
+ }
+
+ // If this panics, max amount of keystream blocks
+ // have been retrieved.
+ self.internal_counter = self.internal_counter.checked_add(1).unwrap();
+
+ let mut wr0 = self.state[0];
+ let mut wr1 = self.state[1];
+ let mut wr2 = self.state[2];
+ let mut wr3 = self.state[3];
+
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+ DOUBLE_ROUND!(wr0, wr1, wr2, wr3);
+
+ let mut iter = inplace.chunks_exact_mut(16);
+
+ if self.is_ietf {
+ wr0 = wr0.wrapping_add(self.state[0]);
+ wr1 = wr1.wrapping_add(self.state[1]);
+ wr2 = wr2.wrapping_add(self.state[2]);
+ wr3 = wr3.wrapping_add(self.state[3]);
+
+ wr0.store_into_le(iter.next().unwrap());
+ wr1.store_into_le(iter.next().unwrap());
+ wr2.store_into_le(iter.next().unwrap());
+ wr3.store_into_le(iter.next().unwrap());
+ } else {
+ wr0.store_into_le(iter.next().unwrap());
+ wr3.store_into_le(iter.next().unwrap());
+ }
+ }
+}
+
+/// XOR keystream into destination array using a temporary buffer for each keystream block.
+pub(crate) fn xor_keystream(
+ ctx: &mut ChaCha20,
+ initial_counter: u32,
+ tmp_block: &mut [u8],
+ bytes: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ debug_assert_eq!(tmp_block.len(), CHACHA_BLOCKSIZE);
+ if bytes.is_empty() {
+ return Err(UnknownCryptoError);
+ }
+
+ for (ctr, out_block) in bytes.chunks_mut(CHACHA_BLOCKSIZE).enumerate() {
+ match initial_counter.checked_add(ctr as u32) {
+ Some(counter) => {
+ ctx.keystream_block(counter, tmp_block);
+ xor_slices!(tmp_block, out_block);
+ }
+ None => return Err(UnknownCryptoError),
+ }
+ }
+
+ Ok(())
+}
+
+/// In-place IETF ChaCha20 encryption as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub(crate) fn encrypt_in_place(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ initial_counter: u32,
+ bytes: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if bytes.is_empty() {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut ctx = ChaCha20::new(secret_key.unprotected_as_bytes(), nonce.as_ref(), true)?;
+ let mut keystream_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+ xor_keystream(&mut ctx, initial_counter, keystream_block.as_mut(), bytes)
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// IETF ChaCha20 encryption as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub fn encrypt(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ initial_counter: u32,
+ plaintext: &[u8],
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if dst_out.len() < plaintext.len() {
+ return Err(UnknownCryptoError);
+ }
+ if plaintext.is_empty() {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut ctx = ChaCha20::new(secret_key.unprotected_as_bytes(), nonce.as_ref(), true)?;
+ let mut keystream_block = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+
+ for (ctr, (p_block, c_block)) in plaintext
+ .chunks(CHACHA_BLOCKSIZE)
+ .zip(dst_out.chunks_mut(CHACHA_BLOCKSIZE))
+ .enumerate()
+ {
+ match initial_counter.checked_add(ctr as u32) {
+ Some(counter) => {
+ // See https://github.com/orion-rs/orion/issues/308
+ ctx.next_produceable()?;
+
+ ctx.keystream_block(counter, keystream_block.as_mut());
+ xor_slices!(p_block, keystream_block.as_mut());
+ c_block[..p_block.len()]
+ .copy_from_slice(&keystream_block.as_ref()[..p_block.len()]);
+ }
+ None => return Err(UnknownCryptoError),
+ }
+ }
+
+ Ok(())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// IETF ChaCha20 decryption as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub fn decrypt(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ initial_counter: u32,
+ ciphertext: &[u8],
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ encrypt(secret_key, nonce, initial_counter, ciphertext, dst_out)
+}
+
+/// HChaCha20 as specified in the [draft-RFC](https://github.com/bikeshedders/xchacha-rfc/blob/master).
+pub(super) fn hchacha20(
+ secret_key: &SecretKey,
+ nonce: &[u8],
+) -> Result<[u8; HCHACHA_OUTSIZE], UnknownCryptoError> {
+ let mut chacha_state = ChaCha20::new(secret_key.unprotected_as_bytes(), nonce, false)?;
+ let mut keystream_block = [0u8; HCHACHA_OUTSIZE];
+ chacha_state.keystream_block(0, &mut keystream_block);
+
+ Ok(keystream_block)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[cfg(feature = "safe_api")]
+ #[test]
+ // See https://github.com/orion-rs/orion/issues/308
+ fn test_plaintext_left_in_dst_out() {
+ let k = SecretKey::generate();
+ let n = Nonce::from_slice(&[0u8; 12]).unwrap();
+ let ic: u32 = u32::MAX - 1;
+
+ let text = [b'x'; 128 + 4];
+ let mut dst_out = [0u8; 128 + 4];
+
+ let _err = encrypt(&k, &n, ic, &text, &mut dst_out).unwrap_err();
+
+ assert_ne!(&[b'x'; 4], &dst_out[dst_out.len() - 4..]);
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_encrypt_decrypt {
+ use super::*;
+ use crate::test_framework::streamcipher_interface::*;
+
+ impl TestingRandom for SecretKey {
+ fn gen() -> Self {
+ Self::generate()
+ }
+ }
+
+ impl TestingRandom for Nonce {
+ fn gen() -> Self {
+ let mut n = [0u8; IETF_CHACHA_NONCESIZE];
+ crate::util::secure_rand_bytes(&mut n).unwrap();
+ Self::from_slice(&n).unwrap()
+ }
+ }
+
+ #[quickcheck]
+ fn prop_streamcipher_interface(input: Vec<u8>, counter: u32) -> bool {
+ let secret_key = SecretKey::generate();
+ let nonce = Nonce::from_slice(&[0u8; IETF_CHACHA_NONCESIZE]).unwrap();
+ StreamCipherTestRunner(encrypt, decrypt, secret_key, nonce, counter, &input, None);
+ test_diff_params_diff_output(&encrypt, &decrypt);
+
+ true
+ }
+ }
+
+ // hex crate uses Vec<u8>, so we need std.
+ mod test_hchacha20 {
+ use super::*;
+
+ use hex::decode;
+
+ #[test]
+ fn test_nonce_length() {
+ assert!(hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 16],).is_ok());
+ assert!(hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 17],).is_err());
+ assert!(hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 15],).is_err());
+ assert!(hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 0],).is_err());
+ }
+
+ #[test]
+ fn test_diff_keys_diff_output() {
+ let keystream1 =
+ hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 16]).unwrap();
+
+ let keystream2 =
+ hchacha20(&SecretKey::from_slice(&[1u8; 32]).unwrap(), &[0u8; 16]).unwrap();
+
+ assert_ne!(keystream1, keystream2);
+ }
+
+ #[test]
+ fn test_diff_nonce_diff_output() {
+ let keystream1 =
+ hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[0u8; 16]).unwrap();
+
+ let keystream2 =
+ hchacha20(&SecretKey::from_slice(&[0u8; 32]).unwrap(), &[1u8; 16]).unwrap();
+
+ assert_ne!(keystream1, keystream2);
+ }
+
+ pub fn hchacha_test_runner(key: &str, nonce: &str, output_expected: &str) {
+ let actual: [u8; 32] = hchacha20(
+ &SecretKey::from_slice(&decode(key).unwrap()).unwrap(),
+ &decode(nonce).unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(&actual, &decode(output_expected).unwrap()[..]);
+ }
+
+ // Testing against Monocypher-generated test vectors
+ // https://github.com/LoupVaillant/Monocypher/tree/master/tests/gen
+ // Pulled at commit: https://github.com/LoupVaillant/Monocypher/commit/39b164a5bf715d1a62689203b059144df76d98e2
+
+ #[test]
+ fn test_case_0() {
+ let key = "e4e4c4054fe35a75d9c0f679ad8770d8227e68e4c1e68ce67ee88e6be251a207";
+ let nonce = "48b3753cff3a6d990163e6b60da1e4e5";
+ let expected_output =
+ "d805447c583fd97a07a2b7ab66be621ad0fa32d63d86ac20588da90b87c1907b";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_1() {
+ let key = "d6a2df78c16c96a52d4fb01ea4ecf70e81ac001b08d6577bd91ce991c4c45c46";
+ let nonce = "bc84d5465fc9139bf17042ae7313181f";
+ let expected_output =
+ "66d1fd5e89a564b55ccf0c339455449c20dfbc9d17081c85fbb430a157777be9";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_2() {
+ let key = "7afb217bd1eceeac1e133aaa9edb441fa88ea3ae0eaa06cb9911b6d218570f92";
+ let nonce = "4a70a7e992b43e0b18578e892e954c40";
+ let expected_output =
+ "41119e28a00a9d3f24b1910495f3058f9db83cbcf12889de84a2fcd7de8dc31b";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_3() {
+ let key = "a51abdb5a85d300c32f391c45d6ef4db043ddcf4214f24ea6ef6b181071f299a";
+ let nonce = "a254a4606ab6a058e0c6fb5598218db7";
+ let expected_output =
+ "04c2f31fdcc7013ac7d10ec82e8d3628c9ab23b08bbf95d6d77ad2dec7e865d6";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_4() {
+ let key = "1deb473f7d04c152e7e857736715dc7b788aca39a3c96a878019e8999c815c57";
+ let nonce = "23dbfbde05e6c71f118afc0dedb5b9f8";
+ let expected_output =
+ "75e9a94daf28b6b8634823325c61cdcb2beeb17a8f7554cc6d5b1b1d2e3592cf";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_5() {
+ let key = "dea398b2d764bca68dfc023a9821939d389e38a072cf1b413bb1517c3fe83abe";
+ let nonce = "bb1cdf3a218abb1b0c01da64c24f59ee";
+ let expected_output =
+ "65a20993e8e69de41d38e94c0796cb7baccd6d80a6e4084e65d0d574fbcb7311";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_6() {
+ let key = "d19cfb8cb3940aba546f0be57895e2cc869fe55aab069c5abcf9e7ba6444a846";
+ let nonce = "e5d73f1c8c5376c1220ff3d9d53eeb65";
+ let expected_output =
+ "a345f5f10ec20b4a744634fbb94e94c9425699b4d57ffeab5403b8fbfb85bae7";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_7() {
+ let key = "cc53599f40d6c8348c353b00172655236cddcd1879ca1f04b35f91adab70b81f";
+ let nonce = "504035fc169964a5ae985e6c11b0b7bb";
+ let expected_output =
+ "11dda56dce88c92641177e2a6e21b11c5ca794912b3bceb9ccb375c87bcc7968";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_8() {
+ let key = "18a51fd77fbffd722aa220efdd8947ca5a5c7fb1c2ebdb9ad1f603801ff22e80";
+ let nonce = "314f716af9c22022fa159dbb4b4d3153";
+ let expected_output =
+ "14759f0e978a9f45a4696739fecb590b4ba6f06536384225333cccba074c8a68";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_9() {
+ let key = "f999b20ab4769eb1d01c057c5295ed042b4536561dce32478b113adb5b605cac";
+ let nonce = "75bcfcacb5e3e811b78e72e398fdd118";
+ let expected_output =
+ "564eb6b2ac2b92270af7c0b054cc7a721313e4ed3651b0970db9dfcdfda27220";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_10() {
+ let key = "bf04c6a7ed0756a3533e3dca02109e1830b739210bd8bffe6a8a542980bd73e9";
+ let nonce = "ca43cdd4eb7173476862df6d2458d6c7";
+ let expected_output =
+ "4f8975d01fb3525a60de55c61190471e86b95cb3e835374d58b003f55eb9819a";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_11() {
+ let key = "4739a0ad2169b9c89edd74e16fbcecc748c25dc338041fc34af0f1bda20eaf3f";
+ let nonce = "ff7b372aa801eb98a1298bc610280737";
+ let expected_output =
+ "06ccde41d10d6466859927bfc9a476dbc84064838ec721261cb548c18bd14c67";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_12() {
+ let key = "50831c8cb43cd6822bf3f6fae0801cb6c843d8066b07346635365fb7d6ee54e5";
+ let nonce = "c9cd6f05d76b2bd4caec8d80b58235cb";
+ let expected_output =
+ "6ed040d7721395fb2c74c8afe252a169ded78e6f2f889e8fb0ec1490533a8154";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_13() {
+ let key = "4268543ab0eb865a948cc5b5f6e31f05f8146bd9495acc459d6d200005ee72c3";
+ let nonce = "bc3e4ae3badfd79adfe46b2ae1045f78";
+ let expected_output =
+ "19b839a6d3424cf2a52d301e70e76cb77368cf9f60945bf43ce4c657aeb1d157";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_14() {
+ let key = "382e04c969df1a2d6a963a79c58401770a383248b5d70bb4adedcbe520fed634";
+ let nonce = "f513b8c2ea6ab37fe633ba7302a5db6c";
+ let expected_output =
+ "fd0739819bae6c98cbde7cb50a80e8d0b359567c50cec1ca7e985745c1cedb3a";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_15() {
+ let key = "2aa209e24478fa1bd6f6ffabe98555e034342cbec07364c54d1e407e282ef08e";
+ let nonce = "dbfdbde936c9d42df58ae15889f5c939";
+ let expected_output =
+ "f5047baa0acf9a603415a09b64268d77712ae902c73490e9c53db593765726db";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_16() {
+ let key = "a3087eaeac1f2a58e2c2763d01b55744c4a65f4db93adff0078c63f090fb607a";
+ let nonce = "90c87defd622e5f55977877cec9ed883";
+ let expected_output =
+ "1d882fa80248882c6bc311a693ebd06b8c09aa2776e6e90df523d12bfeeed77a";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_17() {
+ let key = "12b0411228540cd6dde6e84cd2da59b1871db119e3298e3c12fe8200a47eddf0";
+ let nonce = "49c971cd99f694e3b2a5e25fa37aedf0";
+ let expected_output =
+ "69bb83ccb7bc4deaf60cfe168cb11fad4257222c3523c2d08922564ac0fb74d2";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_18() {
+ let key = "1bf32e7c679a3187e22a635d301ce98ad000ca301049f2e891e403250c3358fc";
+ let nonce = "2030b227bb96e93b88f419afe9f9d660";
+ let expected_output =
+ "d0ed414a875a81db1e4cff7609afdbb2ffcdd575ebc17543fb92de53c6487efb";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_19() {
+ let key = "e013761228051ec5a8f0c093b33fc60e2cd7a9c845434e95d4319d79d1bdaa8f";
+ let nonce = "73853fbd9958e9ffc23a0ecbb7b48dbb";
+ let expected_output =
+ "e3f6c6da6c0300103d665dd877a8b62e23b1361bf3af5bbc2310502131d69be8";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_20() {
+ let key = "a63672d582bb83d92249800324cbc9a6e5b37d36887e7c79093f58ef8f1a0015";
+ let nonce = "85321bfee1714260dd6130cc768d20b1";
+ let expected_output =
+ "97e05360aca70058389d93be38d49fa26df01a4d3b4c4f10c3ec31e0ed64f08e";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_21() {
+ let key = "4d3850f0eec0f8f349110e751c16cdb5ed05516df17479937d942c90eb1fb181";
+ let nonce = "3062bd3f3f6b7668cd8fd3afce0cc752";
+ let expected_output =
+ "77513195542b2ab157cb2e6870c5b1ba143a8423ad276a64152ab923c6f54c06";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_22() {
+ let key = "9b87dfc58eceb951e1e53d9e94793329199c42d004bc0f0dab3adf0cd702e99e";
+ let nonce = "fa5ef6e59d3b201680f8e2d5a4ef7f23";
+ let expected_output =
+ "56a208bd87c5b486b5de50fbe4c1c476532f874147eba529cbb0cbeae8f09b94";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_23() {
+ let key = "f1b6a8e102670a3829a995ae23fbc3a5639e028cd2b5f71bb90c7a1e4a8a0501";
+ let nonce = "7d26e3afc3a88541f6c3f45d71f8a3cc";
+ let expected_output =
+ "a02140057f889e7ab36b4a5066e376dff248d13bd8072c384e23bd8fe4bf7047";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_24() {
+ let key = "31a063ea4aad1b4d00db6f5228e9b9b1561a7f61812b8b79e6af4292580d02ea";
+ let nonce = "4f6266d04244303304510272e383eaa5";
+ let expected_output =
+ "d610d44b8b3c14c7d3782f73405637fd14b7fada717665a9acbd4df6daa89adc";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_25() {
+ let key = "1a8ea7099a74bafa3375b210653a0d2f40b15afd725cf5065066be1cb803dc15";
+ let nonce = "8865ed8d7cca72dcf2b7c6b5d0d045bf";
+ let expected_output =
+ "f10cce296197a056bedbee166183ad6aaa56bdb21c3459296ca54c0bb78317d1";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_26() {
+ let key = "32b063d3da484ba1843e071b61c49ce7f30ba18a4f7ef2730ecd785494839966";
+ let nonce = "f593168e17311913753c59593fc66cb6";
+ let expected_output =
+ "f18115a9568724c25184728f563b65b737219cb0df1b3ce19a8bdcbdf7b8b2be";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_27() {
+ let key = "64c1572251132fc28bf37fd8e96f2327cf7948a1126fd37175a91f483d6b3ad9";
+ let nonce = "2308df7e6daa8bf3efde75f80ad72a49";
+ let expected_output =
+ "06a24cb90abe94cf3ee8e429d8197bc42bc769fbe81119156274f9692aa017a2";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_28() {
+ let key = "ae0794009e21ad33fa4141fe5fa79fed12f6a20f51614dc130f45598e92549b1";
+ let nonce = "13ed6185724507e7fa5a7e8a75b2c7a3";
+ let expected_output =
+ "51d1aec8d64d20e448a377bfa83ccbf71a73a3ad00d062bf6b83c549a7296ef1";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_29() {
+ let key = "ad700919f36a46ea0ffa680857e30188f8a03c7c4b6c11bc39aececec2668723";
+ let nonce = "3682d31887277028e2fd286f2654c681";
+ let expected_output =
+ "a24610a94968df2dc9d197cd0bc55cab08c9dabd444c0efcd2a47fd37016382e";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_30() {
+ let key = "efd9e7ed6b340874e897337d4dcc672811a6cf4b69086e0a57c266424dc1d10e";
+ let nonce = "cbaf0c822cce9e4f17b19e0ece39c180";
+ let expected_output =
+ "6f94a0f8ed7f3fe5ebaa3b8caba016ab64373ffc3c7b1c86e6787f31b4a905ec";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_31() {
+ let key = "a4c756c03c19900280ff6cdebe5174d507c6e0860c38c3537176c58965b74a56";
+ let nonce = "c52b3151bb8a149cf4f82158d57c823f";
+ let expected_output =
+ "50ea3d4f6a45e4a062b2d966e63cac51e093dfb6ab9df6d16bb109bc177b0a38";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_32() {
+ let key = "3a90c6b427912226ff604d9abee1fb8c8d35530a0cd5808e53e308ac580f7318";
+ let nonce = "fe2ab2a4933b5d90db718aa3440fbe9b";
+ let expected_output =
+ "2b57adcc5d26060383c87ef7e055f9aca4addcb2646cbf2cff4edc3f17b72ad5";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_33() {
+ let key = "a17f09716219bdffc93a189e410a6a3e6477fbb05c7c35956c3c0c5f342355fa";
+ let nonce = "0850307998642501c025e3873ebac3cc";
+ let expected_output =
+ "d3a58c49e9fe1ecf2eca169f4d4131cde27279053d562d0429a08ec701aaa39e";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_34() {
+ let key = "d749d8379ae6d830f785ec104897bd723d34ad20c9d36bfe371df46aebc6d459";
+ let nonce = "5d490a770bee4dd0be6a5a0b5e95645c";
+ let expected_output =
+ "c278c0079bd656f1dadf3dec692f19f25339c6557542181716d2a41379740bf2";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_35() {
+ let key = "7dcbc03c27010df3320fe75b0a3ecc8983ad94217e80348fd0f3f54e54b95bb5";
+ let nonce = "48dc2225a264443732b41b861590358d";
+ let expected_output =
+ "b244c408c74f3dcb8bcb72f834a054c554edad0363d761847003dab003ac6848";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_36() {
+ let key = "543894006b73f3d70fc04b15d0c2a5dfa650be5044fb5061811b866be7f9d623";
+ let nonce = "fcb077ee19421610aeb263c57faef006";
+ let expected_output =
+ "fb20ea177cb7225c87122f285d92faf0c2033e2497575f74505255b6d3dfcb96";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_37() {
+ let key = "62d424c07a7aa5005068b262251c0667a4e2e4b12f5df7f509564517887e370b";
+ let nonce = "425fabab1ce9e733ab2911b42074414e";
+ let expected_output =
+ "3a5eb5552cdd267c05c1e4fe936ce8f0eaf7279ff328ed9a42d6d83f7b30416c";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_38() {
+ let key = "387d7247fa5055489bbd4b7d4de256de723566c1c2d3ecee8c10e7d98233dbef";
+ let nonce = "90494951ec91a843f6701f8216a7326b";
+ let expected_output =
+ "8c4bc60a1e05004ec93aef4ae162aeff43d679ea1ba048739c700d6a168bc6cc";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_39() {
+ let key = "241fd57f32e09976de4054797b9aee820e0de381d02852ac13f511918267b703";
+ let nonce = "7330e60ba1c5875a0275f8ccc75cbe98";
+ let expected_output =
+ "9e724c5b0321e2528278a501108f1ae8a14dffaea9b6b138eacef3bd8d4dda41";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_40() {
+ let key = "7c12457eb5614f87f1fdc40118906d02c602059d48ae05ae62d3d607d6bf63c6";
+ let nonce = "760b802483b0e3aaa9dd4f79c6c5e93e";
+ let expected_output =
+ "e5b86f76fbc1f488c44e4d7f304736b752ab6cfb99fcf6910668eeefa4b67c2a";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_41() {
+ let key = "6b51da45018c6bde108f81f9abfa23640b83cfe3fed34bcf6640bf0baf647daf";
+ let nonce = "e9bc99acee972b5a152efa3e69e50f34";
+ let expected_output =
+ "1032b5d539b1c8cd6e0be96db443a08fc759bea8988384435c03b5f00b6e485f";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_42() {
+ let key = "3bc12887fec8e70db73b4b48dce564d83786aca4c6b7e224163ea928771fde37";
+ let nonce = "78c453b35d98deced812fc5685843565";
+ let expected_output =
+ "2279b063dab4c73a96abe02175e694662c65d09eb5889234293c7a1f2911e13d";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_43() {
+ let key = "b73d097601d3558278bd9d7327de5fdaa2b842050b370e837ef811a496169d5f";
+ let nonce = "f768878766c08c45561fdc2aad6469c1";
+ let expected_output =
+ "a8e85a6ab627f08ad415649a9cf9998f4b1065030f3c844e31c8185036af7558";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_44() {
+ let key = "1380c3d3f873c7233c541ea4c43824ecd8bf7e11ac8486208fb685218d46736e";
+ let nonce = "51103d1fae0e8e368f25480ee7328381";
+ let expected_output =
+ "9b84e50804449b594a54240741e21d75d31050d2612f4cbc651fea2f25bd9c1f";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_45() {
+ let key = "c2f8b252a18a29c44dbfbb62cbe6c3dfd4db55378734d8110b8f20f1d1ada6dd";
+ let nonce = "d4da48fb09c06580eb46bbc5ca62bfab";
+ let expected_output =
+ "315c3fe1009e438762a72f27e7a68b8ccb2c0b60bf79cb6e48123db0c42d4aeb";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_46() {
+ let key = "40b184271b73b710d40cb63435042c9b526d1e5c3a77bfc516a2bcb4cc27ecae";
+ let nonce = "b3451318590c84e311dd1e876f527d81";
+ let expected_output =
+ "cbbde3a3412504c1f684aa273ee691159edc9f44e306360278d63d4ee2f1faa4";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_47() {
+ let key = "ec81df06c7e426b729aebb02be30c846eb228490df4a0e6c688aaaa6bf05d144";
+ let nonce = "28335f2652926bfdfe32dfd789173ba8";
+ let expected_output =
+ "522b522e4cf9aa1e80126a446ed7b9665af3e781a3d5afdce43a5fe0cdbd4351";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_48() {
+ let key = "60fa0114802ee333d7c49ccaad8108db470c882514716592e57aba26bb75049b";
+ let nonce = "75db088bd1a89c6a67fb76b96c987478";
+ let expected_output =
+ "e004cc12dfdb74268e59958385e2a1c6ff31e31664838971629f5bbf88f4ed51";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ #[test]
+ fn test_case_49() {
+ let key = "bfba2449a607f3cca1c911d3b7d9cb972bcd84b0246189c7820032e031949f1e";
+ let nonce = "97e8ad5eb5a75cc805900850969de48e";
+ let expected_output =
+ "19faebfbb954552fcfbf9b91f271c9397a15c641733c394a9cb731c286c68645";
+ hchacha_test_runner(key, nonce, expected_output);
+ }
+ }
+}
+
+// Testing private functions in the module.
+#[cfg(test)]
+mod private {
+ use super::*;
+
+ mod test_init_state {
+ use super::*;
+
+ #[test]
+ fn test_nonce_length() {
+ assert!(ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; 15], true).is_err());
+ assert!(ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; 10], true).is_err());
+ assert!(
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; IETF_CHACHA_NONCESIZE], true).is_ok()
+ );
+
+ assert!(ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; 15], false).is_err());
+ assert!(ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; 17], false).is_err());
+ assert!(
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; HCHACHA_NONCESIZE], false).is_ok()
+ );
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_test_nonce_length_ietf(nonce: Vec<u8>) -> bool {
+ if nonce.len() == IETF_CHACHA_NONCESIZE {
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &nonce[..], true).is_ok()
+ } else {
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &nonce[..], true).is_err()
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ // Always fail to initialize state while the nonce is not
+ // the correct length. If it is correct length, never panic.
+ fn prop_test_nonce_length_hchacha(nonce: Vec<u8>) -> bool {
+ if nonce.len() == HCHACHA_NONCESIZE {
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &nonce, false).is_ok()
+ } else {
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &nonce, false).is_err()
+ }
+ }
+ }
+
+ mod test_encrypt_in_place {
+ use super::*;
+
+ #[test]
+ #[should_panic]
+ #[cfg(debug_assertions)]
+ fn test_xor_keystream_err_bad_tmp() {
+ let mut ctx =
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; IETF_CHACHA_NONCESIZE], true).unwrap();
+ let mut tmp = [0u8; CHACHA_BLOCKSIZE - 1];
+ let mut out = [0u8; CHACHA_BLOCKSIZE];
+ xor_keystream(&mut ctx, 0, &mut tmp, &mut out).unwrap();
+ }
+
+ #[test]
+ fn test_xor_keystream_err_empty_input() {
+ let mut ctx =
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; IETF_CHACHA_NONCESIZE], true).unwrap();
+ let mut tmp = [0u8; CHACHA_BLOCKSIZE];
+ let mut out = [0u8; 0];
+ assert!(xor_keystream(&mut ctx, 0, &mut tmp, &mut out).is_err());
+ }
+
+ #[test]
+ fn test_enc_in_place_err_empty_input() {
+ let n = Nonce::from([0u8; IETF_CHACHA_NONCESIZE]);
+ let sk = SecretKey::from([0u8; CHACHA_KEYSIZE]);
+ let mut out = [0u8; 0];
+ assert!(encrypt_in_place(&sk, &n, 0, &mut out).is_err());
+ }
+ }
+
+ mod test_keystream_block {
+ use super::*;
+
+ #[test]
+ fn test_xor_keystream_block_ignore_counter_when_hchacha() {
+ let mut chacha_state_hchacha =
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; HCHACHA_NONCESIZE], false).unwrap();
+
+ let mut hchacha_keystream_block_zero = [0u8; HCHACHA_OUTSIZE];
+ let mut hchacha_keystream_block_max = [0u8; HCHACHA_OUTSIZE];
+
+ chacha_state_hchacha.keystream_block(0, &mut hchacha_keystream_block_zero);
+ chacha_state_hchacha.keystream_block(u32::MAX, &mut hchacha_keystream_block_max);
+
+ assert_eq!(hchacha_keystream_block_zero, hchacha_keystream_block_max);
+ }
+
+ #[cfg(debug_assertions)]
+ #[test]
+ #[should_panic]
+ fn test_xor_keystream_block_invalid_blocksize_ietf() {
+ let mut chacha_state_ietf =
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; IETF_CHACHA_NONCESIZE], true).unwrap();
+
+ let mut ietf_keystream_block = [0u8; CHACHA_BLOCKSIZE];
+ let mut hchacha_keystream_block = [0u8; HCHACHA_OUTSIZE];
+
+ chacha_state_ietf.keystream_block(0, &mut ietf_keystream_block);
+ chacha_state_ietf.keystream_block(0, &mut hchacha_keystream_block);
+ }
+
+ #[cfg(debug_assertions)]
+ #[test]
+ #[should_panic]
+ fn test_xor_keystream_block_invalid_blocksize_hchacha() {
+ let mut chacha_state_hchacha =
+ ChaCha20::new(&[0u8; CHACHA_KEYSIZE], &[0u8; HCHACHA_NONCESIZE], false).unwrap();
+
+ let mut ietf_keystream_block = [0u8; CHACHA_BLOCKSIZE];
+ let mut hchacha_keystream_block = [0u8; HCHACHA_OUTSIZE];
+
+ chacha_state_hchacha.keystream_block(0, &mut hchacha_keystream_block);
+ chacha_state_hchacha.keystream_block(0, &mut ietf_keystream_block);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_xor_keystream_panic_on_too_much_keystream_data_ietf() {
+ let mut chacha_state_ietf = ChaCha20 {
+ state: [
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ ],
+ internal_counter: (u32::MAX - 128),
+ is_ietf: true,
+ };
+
+ let mut keystream_block = [0u8; CHACHA_BLOCKSIZE];
+
+ for amount in 0..(128 + 1) {
+ chacha_state_ietf.keystream_block(amount, &mut keystream_block);
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_xor_keystream_panic_on_too_much_keystream_data_hchacha() {
+ let mut chacha_state_ietf = ChaCha20 {
+ state: [
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ ],
+ internal_counter: (u32::MAX - 128),
+ is_ietf: false,
+ };
+
+ let mut keystream_block = [0u8; HCHACHA_OUTSIZE];
+
+ for _ in 0..(128 + 1) {
+ chacha_state_ietf.keystream_block(0, &mut keystream_block);
+ }
+ }
+
+ #[test]
+ fn test_error_if_internal_counter_would_overflow() {
+ let mut chacha_state = ChaCha20 {
+ state: [
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ U32x4(0, 0, 0, 0),
+ ],
+ internal_counter: (u32::MAX - 2),
+ is_ietf: false,
+ };
+
+ assert!(chacha_state.next_produceable().is_ok());
+ chacha_state.internal_counter += 1;
+ assert!(chacha_state.next_produceable().is_ok());
+ chacha_state.internal_counter += 1;
+ assert!(chacha_state.next_produceable().is_err());
+ }
+ }
+}
+
+// Testing any test vectors that aren't put into library's /tests folder.
+#[cfg(test)]
+mod test_vectors {
+ use super::*;
+
+ // NOTE: These PartialEq implementation should only be available in testing.
+ #[cfg(test)]
+ impl PartialEq for U32x4 {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0 && self.1 == other.1 && self.2 == other.2 && self.3 == other.3
+ }
+ }
+
+ // Convenience function for testing.
+ fn init(key: &[u8], nonce: &[u8]) -> Result<ChaCha20, UnknownCryptoError> {
+ ChaCha20::new(key, nonce, true)
+ }
+ #[test]
+ fn rfc8439_chacha20_block_results() {
+ let key = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x1c, 0x1d, 0x1e, 0x1f,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ ];
+ let expected = [
+ 0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15, 0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20,
+ 0x71, 0xc4, 0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03, 0x04, 0x22, 0xaa, 0x9a,
+ 0xc3, 0xd4, 0x6c, 0x4e, 0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09, 0x14, 0xc2,
+ 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2, 0xb5, 0x12, 0x9c, 0xd1, 0xde, 0x16, 0x4e, 0xb9,
+ 0xcb, 0xd0, 0x83, 0xe8, 0xa2, 0x50, 0x3c, 0x4e,
+ ];
+
+ let expected_init = [
+ U32x4(0x61707865, 0x3320646e, 0x79622d32, 0x6b206574),
+ U32x4(0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c),
+ U32x4(0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c),
+ U32x4(0x00000001, 0x09000000, 0x4a000000, 0x00000000),
+ ];
+ // Test initial key-setup
+ let mut state = init(&key, &nonce).unwrap();
+ // Set block counter
+ state.state[3].0 = 1;
+ assert!(state.state[..] == expected_init[..]);
+
+ let mut kb = [0u8; 64];
+ state.keystream_block(1, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_chacha20_block_test_1() {
+ let key = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+ let expected = [
+ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86,
+ 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc,
+ 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 0x77, 0x24,
+ 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
+ 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut kb = [0u8; 64];
+ state.keystream_block(0, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_chacha20_block_test_2() {
+ let key = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+ let expected = [
+ 0x9f, 0x07, 0xe7, 0xbe, 0x55, 0x51, 0x38, 0x7a, 0x98, 0xba, 0x97, 0x7c, 0x73, 0x2d,
+ 0x08, 0x0d, 0xcb, 0x0f, 0x29, 0xa0, 0x48, 0xe3, 0x65, 0x69, 0x12, 0xc6, 0x53, 0x3e,
+ 0x32, 0xee, 0x7a, 0xed, 0x29, 0xb7, 0x21, 0x76, 0x9c, 0xe6, 0x4e, 0x43, 0xd5, 0x71,
+ 0x33, 0xb0, 0x74, 0xd8, 0x39, 0xd5, 0x31, 0xed, 0x1f, 0x28, 0x51, 0x0a, 0xfb, 0x45,
+ 0xac, 0xe1, 0x0a, 0x1f, 0x4b, 0x79, 0x4d, 0x6f,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut kb = [0u8; 64];
+ state.keystream_block(1, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_chacha20_block_test_3() {
+ let key = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+ let expected = [
+ 0x3a, 0xeb, 0x52, 0x24, 0xec, 0xf8, 0x49, 0x92, 0x9b, 0x9d, 0x82, 0x8d, 0xb1, 0xce,
+ 0xd4, 0xdd, 0x83, 0x20, 0x25, 0xe8, 0x01, 0x8b, 0x81, 0x60, 0xb8, 0x22, 0x84, 0xf3,
+ 0xc9, 0x49, 0xaa, 0x5a, 0x8e, 0xca, 0x00, 0xbb, 0xb4, 0xa7, 0x3b, 0xda, 0xd1, 0x92,
+ 0xb5, 0xc4, 0x2f, 0x73, 0xf2, 0xfd, 0x4e, 0x27, 0x36, 0x44, 0xc8, 0xb3, 0x61, 0x25,
+ 0xa6, 0x4a, 0xdd, 0xeb, 0x00, 0x6c, 0x13, 0xa0,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut kb = [0u8; 64];
+ state.keystream_block(1, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_chacha20_block_test_4() {
+ let key = [
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+ let expected = [
+ 0x72, 0xd5, 0x4d, 0xfb, 0xf1, 0x2e, 0xc4, 0x4b, 0x36, 0x26, 0x92, 0xdf, 0x94, 0x13,
+ 0x7f, 0x32, 0x8f, 0xea, 0x8d, 0xa7, 0x39, 0x90, 0x26, 0x5e, 0xc1, 0xbb, 0xbe, 0xa1,
+ 0xae, 0x9a, 0xf0, 0xca, 0x13, 0xb2, 0x5a, 0xa2, 0x6c, 0xb4, 0xa6, 0x48, 0xcb, 0x9b,
+ 0x9d, 0x1b, 0xe6, 0x5b, 0x2c, 0x09, 0x24, 0xa6, 0x6c, 0x54, 0xd5, 0x45, 0xec, 0x1b,
+ 0x73, 0x74, 0xf4, 0x87, 0x2e, 0x99, 0xf0, 0x96,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut kb = [0u8; 64];
+ state.keystream_block(2, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_chacha20_block_test_5() {
+ let key = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ ];
+ let expected = [
+ 0xc2, 0xc6, 0x4d, 0x37, 0x8c, 0xd5, 0x36, 0x37, 0x4a, 0xe2, 0x04, 0xb9, 0xef, 0x93,
+ 0x3f, 0xcd, 0x1a, 0x8b, 0x22, 0x88, 0xb3, 0xdf, 0xa4, 0x96, 0x72, 0xab, 0x76, 0x5b,
+ 0x54, 0xee, 0x27, 0xc7, 0x8a, 0x97, 0x0e, 0x0e, 0x95, 0x5c, 0x14, 0xf3, 0xa8, 0x8e,
+ 0x74, 0x1b, 0x97, 0xc2, 0x86, 0xf7, 0x5f, 0x8f, 0xc2, 0x99, 0xe8, 0x14, 0x83, 0x62,
+ 0xfa, 0x19, 0x8a, 0x39, 0x53, 0x1b, 0xed, 0x6d,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut kb = [0u8; 64];
+ state.keystream_block(0, &mut kb);
+
+ assert_eq!(kb[..], expected[..]);
+ }
+
+ #[test]
+ fn rfc8439_key_schedule() {
+ let key = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x1c, 0x1d, 0x1e, 0x1f,
+ ];
+ let nonce = [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00,
+ ];
+ // First block setup expected
+ let first_state = [
+ U32x4(0x61707865, 0x3320646e, 0x79622d32, 0x6b206574),
+ U32x4(0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c),
+ U32x4(0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c),
+ U32x4(0x00000001, 0x00000000, 0x4a000000, 0x00000000),
+ ];
+ // Second block setup expected
+ let second_state = [
+ U32x4(0x61707865, 0x3320646e, 0x79622d32, 0x6b206574),
+ U32x4(0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c),
+ U32x4(0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c),
+ U32x4(0x00000002, 0x00000000, 0x4a000000, 0x00000000),
+ ];
+
+ // Expected keystream
+ let expected_keystream = [
+ 0x22, 0x4f, 0x51, 0xf3, 0x40, 0x1b, 0xd9, 0xe1, 0x2f, 0xde, 0x27, 0x6f, 0xb8, 0x63,
+ 0x1d, 0xed, 0x8c, 0x13, 0x1f, 0x82, 0x3d, 0x2c, 0x06, 0xe2, 0x7e, 0x4f, 0xca, 0xec,
+ 0x9e, 0xf3, 0xcf, 0x78, 0x8a, 0x3b, 0x0a, 0xa3, 0x72, 0x60, 0x0a, 0x92, 0xb5, 0x79,
+ 0x74, 0xcd, 0xed, 0x2b, 0x93, 0x34, 0x79, 0x4c, 0xba, 0x40, 0xc6, 0x3e, 0x34, 0xcd,
+ 0xea, 0x21, 0x2c, 0x4c, 0xf0, 0x7d, 0x41, 0xb7, 0x69, 0xa6, 0x74, 0x9f, 0x3f, 0x63,
+ 0x0f, 0x41, 0x22, 0xca, 0xfe, 0x28, 0xec, 0x4d, 0xc4, 0x7e, 0x26, 0xd4, 0x34, 0x6d,
+ 0x70, 0xb9, 0x8c, 0x73, 0xf3, 0xe9, 0xc5, 0x3a, 0xc4, 0x0c, 0x59, 0x45, 0x39, 0x8b,
+ 0x6e, 0xda, 0x1a, 0x83, 0x2c, 0x89, 0xc1, 0x67, 0xea, 0xcd, 0x90, 0x1d, 0x7e, 0x2b,
+ 0xf3, 0x63,
+ ];
+
+ let mut state = init(&key, &nonce).unwrap();
+ let mut actual_keystream = [0u8; 128];
+
+ state.keystream_block(1, &mut actual_keystream[..64]);
+ assert!(first_state == state.state);
+
+ state.keystream_block(2, &mut actual_keystream[64..]);
+ assert!(second_state == state.state);
+
+ assert_eq!(
+ actual_keystream[..expected_keystream.len()].as_ref(),
+ expected_keystream.as_ref()
+ );
+ }
+}
diff --git a/vendor/orion/src/hazardous/stream/mod.rs b/vendor/orion/src/hazardous/stream/mod.rs
new file mode 100644
index 0000000..a211b7d
--- /dev/null
+++ b/vendor/orion/src/hazardous/stream/mod.rs
@@ -0,0 +1,27 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+/// IETF ChaCha20 as specified in the [RFC 8439](https://tools.ietf.org/html/rfc8439).
+pub mod chacha20;
+
+/// XChaCha20 as specified in the [draft-irtf-cfrg-xchacha-03](https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-03).
+pub mod xchacha20;
diff --git a/vendor/orion/src/hazardous/stream/xchacha20.rs b/vendor/orion/src/hazardous/stream/xchacha20.rs
new file mode 100644
index 0000000..b8940aa
--- /dev/null
+++ b/vendor/orion/src/hazardous/stream/xchacha20.rs
@@ -0,0 +1,176 @@
+// MIT License
+
+// Copyright (c) 2018-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:
+//! - `secret_key`: The secret key.
+//! - `nonce`: The nonce value.
+//! - `initial_counter`: The initial counter value. In most cases, this is `0`.
+//! - `ciphertext`: The encrypted data.
+//! - `plaintext`: The data to be encrypted.
+//! - `dst_out`: Destination array that will hold the ciphertext/plaintext after
+//! encryption/decryption.
+//!
+//! `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` or `ciphertext`.
+//! - `plaintext` or `ciphertext` is empty.
+//! - The `initial_counter` is high enough to cause a potential overflow.
+//!
+//! Even though `dst_out` is allowed to be of greater length than `plaintext`,
+//! the `ciphertext` produced by `chacha20`/`xchacha20` will always be of the
+//! same length as the `plaintext`.
+//!
+//! # 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.
+//! - Functions herein do not provide any data integrity. If you need
+//! data integrity, which is nearly ***always the case***, you should use an
+//! AEAD construction instead. See the [`aead`](super::aead) module for this.
+//! - Only a nonce for XChaCha20 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()`].
+//!
+//! # Recommendation:
+//! - It is recommended to use [`XChaCha20Poly1305`] when possible.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::stream::xchacha20;
+//!
+//! let secret_key = xchacha20::SecretKey::generate();
+//! let nonce = xchacha20::Nonce::generate();
+//! let message = "Data to protect".as_bytes();
+//!
+//! // Length of this message is 15
+//!
+//! let mut dst_out_pt = [0u8; 15];
+//! let mut dst_out_ct = [0u8; 15];
+//!
+//! xchacha20::encrypt(&secret_key, &nonce, 0, message, &mut dst_out_ct)?;
+//!
+//! xchacha20::decrypt(&secret_key, &nonce, 0, &dst_out_ct, &mut dst_out_pt)?;
+//!
+//! assert_eq!(dst_out_pt, message);
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`SecretKey::generate()`]: xchacha20::SecretKey::generate()
+//! [`Nonce::generate()`]: xchacha20::Nonce::generate()
+//! [`XChaCha20Poly1305`]: super::aead::xchacha20poly1305
+pub use crate::hazardous::stream::chacha20::SecretKey;
+use crate::{
+ errors::UnknownCryptoError,
+ hazardous::stream::chacha20::{self, Nonce as IETFNonce, IETF_CHACHA_NONCESIZE},
+};
+
+/// The nonce size for XChaCha20.
+pub const XCHACHA_NONCESIZE: usize = 24;
+
+construct_public! {
+ /// A type that represents a `Nonce` that XChaCha20, XChaCha20-Poly1305 use.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 24 bytes.
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Nonce, test_nonce, XCHACHA_NONCESIZE, XCHACHA_NONCESIZE, XCHACHA_NONCESIZE)
+}
+
+impl_from_trait!(Nonce, XCHACHA_NONCESIZE);
+
+/// Generate a subkey using HChaCha20 for XChaCha20 and corresponding nonce.
+pub(crate) fn subkey_and_nonce(secret_key: &SecretKey, nonce: &Nonce) -> (SecretKey, IETFNonce) {
+ // .unwrap() should not be able to panic because we pass a 16-byte nonce.
+ let subkey: SecretKey =
+ SecretKey::from(chacha20::hchacha20(secret_key, &nonce.as_ref()[0..16]).unwrap());
+ let mut prefixed_nonce = [0u8; IETF_CHACHA_NONCESIZE];
+ prefixed_nonce[4..IETF_CHACHA_NONCESIZE].copy_from_slice(&nonce.as_ref()[16..24]);
+
+ (subkey, IETFNonce::from(prefixed_nonce))
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// XChaCha20 encryption as specified in the [draft RFC](https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-03).
+pub fn encrypt(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ initial_counter: u32,
+ plaintext: &[u8],
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ let (subkey, ietf_nonce) = subkey_and_nonce(secret_key, nonce);
+
+ chacha20::encrypt(&subkey, &ietf_nonce, initial_counter, plaintext, dst_out)
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// XChaCha20 decryption as specified in the [draft RFC](https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-03).
+pub fn decrypt(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ initial_counter: u32,
+ ciphertext: &[u8],
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ encrypt(secret_key, nonce, initial_counter, ciphertext, dst_out)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+mod public {
+ use super::*;
+
+ mod test_encrypt_decrypt {
+ use super::*;
+ use crate::test_framework::streamcipher_interface::*;
+
+ impl TestingRandom for Nonce {
+ fn gen() -> Self {
+ Self::generate()
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_streamcipher_interface(input: Vec<u8>, counter: u32) -> bool {
+ let secret_key = SecretKey::generate();
+ let nonce = Nonce::generate();
+ StreamCipherTestRunner(encrypt, decrypt, secret_key, nonce, counter, &input, None);
+ test_diff_params_diff_output(&encrypt, &decrypt);
+
+ true
+ }
+ }
+}
diff --git a/vendor/orion/src/high_level/aead.rs b/vendor/orion/src/high_level/aead.rs
new file mode 100644
index 0000000..4159ef8
--- /dev/null
+++ b/vendor/orion/src/high_level/aead.rs
@@ -0,0 +1,631 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+//! Authenticated secret-key encryption.
+//!
+//! # Use case:
+//! `orion::aead` can be used to encrypt data in a way that detects if the
+//! encrypted data has been tampered with before decrypting it.
+//!
+//! An example of this could be sending messages across networks, where
+//! confidentiality and authenticity of these messages is required.
+//!
+//! # About:
+//! - Both one-shot functions and a [`streaming`] API are provided.
+//! - The nonce is automatically generated.
+//! - Returns a vector where the first 24 bytes are the nonce and the rest is
+//! the authenticated ciphertext with the last 16 bytes being the corresponding Poly1305 tag.
+//! - Uses XChaCha20Poly1305 with no additional data.
+//! - When using [`seal`] and [`open`] then the separation of tags, nonces and
+//! ciphertext are automatically handled.
+//!
+//! # Parameters:
+//! - `plaintext`: The data to be encrypted.
+//! - `secret_key`: The secret key used to encrypt the `plaintext`.
+//! - `ciphertext_with_tag_and_nonce`: The data to be decrypted with the first
+//! 24 bytes being the nonce and the last 16 bytes being the corresponding Poly1305 tag.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - `secret_key` is not 32 bytes.
+//! - The `plaintext` is empty.
+//! - `ciphertext_with_tag_and_nonce` is less than 41 bytes
+//! ([`XCHACHA_NONCESIZE`] + [`POLY1305_OUTSIZE`] + 1).
+//! - The received tag does not match the calculated tag when calling [`open`].
+//! - `plaintext.len()` + [`XCHACHA_NONCESIZE`] + [`POLY1305_OUTSIZE`] overflows when calling [`seal`].
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2^32-1 * 64 bytes of data are processed.
+//! - Failure to generate random bytes securely.
+//!
+//! # 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.
+//! - To securely generate a strong key, use [`SecretKey::default()`].
+//! - The length of the `plaintext` is not hidden, only its contents.
+//!
+//! # Example:
+//! ```rust
+//! use orion::aead;
+//!
+//! let secret_key = aead::SecretKey::default();
+//! let ciphertext = aead::seal(&secret_key, b"Secret message")?;
+//! let decrypted_data = aead::open(&secret_key, &ciphertext)?;
+//!
+//! assert_eq!(decrypted_data, b"Secret message");
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use super::hltypes::SecretKey;
+use crate::{
+ errors::UnknownCryptoError,
+ hazardous::{
+ aead,
+ mac::poly1305::POLY1305_OUTSIZE,
+ stream::{
+ chacha20,
+ xchacha20::{Nonce, XCHACHA_NONCESIZE},
+ },
+ },
+};
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Authenticated encryption using XChaCha20Poly1305.
+pub fn seal(secret_key: &SecretKey, plaintext: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
+ if plaintext.is_empty() {
+ return Err(UnknownCryptoError);
+ }
+
+ let out_len = match plaintext
+ .len()
+ .checked_add(XCHACHA_NONCESIZE + POLY1305_OUTSIZE)
+ {
+ Some(min_out_len) => min_out_len,
+ None => return Err(UnknownCryptoError),
+ };
+
+ let mut dst_out = vec![0u8; out_len];
+ let nonce = Nonce::generate();
+ dst_out[..XCHACHA_NONCESIZE].copy_from_slice(nonce.as_ref());
+
+ aead::xchacha20poly1305::seal(
+ &chacha20::SecretKey::from_slice(secret_key.unprotected_as_bytes())?,
+ &nonce,
+ plaintext,
+ None,
+ &mut dst_out[XCHACHA_NONCESIZE..],
+ )?;
+
+ Ok(dst_out)
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Authenticated decryption using XChaCha20Poly1305.
+pub fn open(
+ secret_key: &SecretKey,
+ ciphertext_with_tag_and_nonce: &[u8],
+) -> Result<Vec<u8>, UnknownCryptoError> {
+ // Avoid empty ciphertexts
+ if ciphertext_with_tag_and_nonce.len() <= (XCHACHA_NONCESIZE + POLY1305_OUTSIZE) {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut dst_out =
+ vec![0u8; ciphertext_with_tag_and_nonce.len() - (XCHACHA_NONCESIZE + POLY1305_OUTSIZE)];
+
+ aead::xchacha20poly1305::open(
+ &chacha20::SecretKey::from_slice(secret_key.unprotected_as_bytes())?,
+ &Nonce::from_slice(&ciphertext_with_tag_and_nonce[..XCHACHA_NONCESIZE])?,
+ &ciphertext_with_tag_and_nonce[XCHACHA_NONCESIZE..],
+ None,
+ &mut dst_out,
+ )?;
+
+ Ok(dst_out)
+}
+
+pub mod streaming {
+ //! Streaming AEAD based on XChaCha20Poly1305.
+ //!
+ //! # Use case:
+ //! This can be used to encrypt and authenticate a stream of data. It prevents the
+ //! modification, reordering, dropping or duplication of messages. Nonce management is handled automatically.
+ //!
+ //! An example of this could be the encryption of files that are too large to encrypt in one piece.
+ //!
+ //! # About:
+ //! This implementation is based on and compatible with the ["secretstream" API] of libsodium.
+ //!
+ //! # Parameters:
+ //! - `secret_key`: The secret key.
+ //! - `nonce`: The nonce value.
+ //! - `plaintext`: The data to be encrypted.
+ //! - `ciphertext`: The encrypted data with a Poly1305 tag and a [`StreamTag`] indicating its function.
+ //! - `tag`: Indicates the type of message. The `tag` is a part of the output when encrypting. It
+ //! is encrypted and authenticated.
+ //!
+ //! # Errors:
+ //! An error will be returned if:
+ //! - `secret_key` is not 32 bytes.
+ //! - The length of `ciphertext` is not at least [`ABYTES`].
+ //! - The received mac does not match the calculated mac when decrypting. This can indicate
+ //! a dropped or reordered message within the stream.
+ //! - More than 2^32-3 * 64 bytes of data are processed when encrypting/decrypting a single chunk.
+ //! - [`ABYTES`] + `plaintext.len()` overflows when encrypting.
+ //!
+ //! # Panics:
+ //! A panic will occur if:
+ //! - 64 + (`ciphertext.len()` - [`ABYTES`]) overflows when decrypting.
+ //! - Failure to generate random bytes securely.
+ //!
+ //! # Security:
+ //! - It is critical for security that a given nonce is not re-used with a given
+ //! key.
+ //! - To securely generate a strong key, use [`SecretKey::generate()`].
+ //! - The length of the messages is leaked.
+ //! - It is recommended to use `StreamTag::Finish` as tag for the last message. This allows the
+ //! decrypting side to detect if messages at the end of the stream are lost.
+ //!
+ //! # Example:
+ //! ```rust
+ //! use orion::aead::streaming::*;
+ //! use orion::aead::SecretKey;
+ //!
+ //! let chunk_size: usize = 128; // The size of the chunks you wish to split the stream into.
+ //! let src = [255u8; 4096]; // Some example input stream.
+ //! let mut out: Vec<Vec<u8>> = Vec::with_capacity(4096 / 128);
+ //!
+ //! let secret_key = SecretKey::default();
+ //!
+ //! // Encryption:
+ //! let (mut sealer, nonce) = StreamSealer::new(&secret_key)?;
+ //!
+ //! for (n_chunk, src_chunk) in src.chunks(chunk_size).enumerate() {
+ //! let encrypted_chunk =
+ //! if src_chunk.len() != chunk_size || n_chunk + 1 == src.len() / chunk_size {
+ //! // We've reached the end of the input source,
+ //! // so we mark it with the Finish tag.
+ //! sealer.seal_chunk(src_chunk, &StreamTag::Finish)?
+ //! } else {
+ //! // Just a normal chunk
+ //! sealer.seal_chunk(src_chunk, &StreamTag::Message)?
+ //! };
+ //! // Save the encrypted chunk somewhere
+ //! out.push(encrypted_chunk);
+ //! }
+ //!
+ //! // Decryption:
+ //! let mut opener = StreamOpener::new(&secret_key, &nonce)?;
+ //!
+ //! for (n_chunk, src_chunk) in out.iter().enumerate() {
+ //! let (_decrypted_chunk, tag) = opener.open_chunk(src_chunk)?;
+ //!
+ //! if src_chunk.len() != chunk_size + ABYTES || n_chunk + 1 == out.len() {
+ //! // We've reached the end of the input source,
+ //! // so we check if the last chunk is also set as Finish.
+ //! assert_eq!(tag, StreamTag::Finish, "Stream has been truncated!");
+ //! }
+ //! }
+ //!
+ //! # Ok::<(), orion::errors::UnknownCryptoError>(())
+ //! ```
+ //! [`ABYTES`]: crate::hazardous::aead::streaming::ABYTES
+ //! [`StreamTag`]: crate::hazardous::aead::streaming::StreamTag
+ //! [`SecretKey::generate()`]: super::SecretKey::generate
+ //! ["secretstream" API]: https://download.libsodium.org/doc/secret-key_cryptography/secretstream
+
+ use super::*;
+ pub use crate::hazardous::aead::streaming::Nonce;
+ pub use crate::hazardous::aead::streaming::StreamTag;
+ pub use crate::hazardous::aead::streaming::ABYTES;
+
+ #[derive(Debug)]
+ /// Streaming authenticated encryption.
+ pub struct StreamSealer {
+ internal_sealer: aead::streaming::StreamXChaCha20Poly1305,
+ }
+
+ impl StreamSealer {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize a `StreamSealer` struct with a given key.
+ pub fn new(secret_key: &SecretKey) -> Result<(Self, Nonce), UnknownCryptoError> {
+ let nonce = Nonce::generate();
+ let sk = &aead::streaming::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
+
+ let sealer = Self {
+ internal_sealer: aead::streaming::StreamXChaCha20Poly1305::new(sk, &nonce),
+ };
+ Ok((sealer, nonce))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Encrypts `plaintext`. The `StreamTag` indicates the type of message.
+ pub fn seal_chunk(
+ &mut self,
+ plaintext: &[u8],
+ tag: &StreamTag,
+ ) -> Result<Vec<u8>, UnknownCryptoError> {
+ let sealed_chunk_len = plaintext.len().checked_add(ABYTES);
+ if sealed_chunk_len.is_none() {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut sealed_chunk = vec![0u8; sealed_chunk_len.unwrap()];
+ self.internal_sealer
+ .seal_chunk(plaintext, None, &mut sealed_chunk, tag)?;
+
+ Ok(sealed_chunk)
+ }
+ }
+
+ #[derive(Debug)]
+ /// Streaming authenticated decryption.
+ pub struct StreamOpener {
+ internal_sealer: aead::streaming::StreamXChaCha20Poly1305,
+ }
+
+ impl StreamOpener {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Initialize a `StreamOpener` struct with a given key and nonce.
+ pub fn new(secret_key: &SecretKey, nonce: &Nonce) -> Result<Self, UnknownCryptoError> {
+ let sk = &chacha20::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
+
+ Ok(Self {
+ internal_sealer: aead::streaming::StreamXChaCha20Poly1305::new(sk, nonce),
+ })
+ }
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Decrypts `ciphertext`. Returns the decrypted data and the `StreamTag` indicating the type of message.
+ pub fn open_chunk(
+ &mut self,
+ ciphertext: &[u8],
+ ) -> Result<(Vec<u8>, StreamTag), UnknownCryptoError> {
+ if ciphertext.len() < ABYTES {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut opened_chunk = vec![0u8; ciphertext.len() - ABYTES];
+ let tag = self
+ .internal_sealer
+ .open_chunk(ciphertext, None, &mut opened_chunk)?;
+
+ Ok((opened_chunk, tag))
+ }
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ mod test_seal_open {
+ use super::*;
+
+ #[test]
+ fn test_auth_enc_encryption_decryption() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+
+ let dst_ciphertext = seal(&key, plaintext).unwrap();
+ assert_eq!(dst_ciphertext.len(), plaintext.len() + (24 + 16));
+ let dst_plaintext = open(&key, &dst_ciphertext).unwrap();
+ assert_eq!(plaintext, &dst_plaintext[..]);
+ }
+
+ #[test]
+ fn test_auth_enc_plaintext_empty_err() {
+ let key = SecretKey::default();
+ let plaintext = "".as_bytes();
+
+ assert!(seal(&key, plaintext).is_err());
+ }
+
+ #[test]
+ fn test_auth_enc_ciphertext_less_than_41_err() {
+ let key = SecretKey::default();
+ let ciphertext = [0u8; XCHACHA_NONCESIZE + POLY1305_OUTSIZE];
+
+ assert!(open(&key, &ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_modified_nonce_err() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = seal(&key, plaintext).unwrap();
+ // Modify nonce
+ dst_ciphertext[10] ^= 1;
+ assert!(open(&key, &dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_modified_ciphertext_err() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = seal(&key, plaintext).unwrap();
+ // Modify ciphertext
+ dst_ciphertext[25] ^= 1;
+ assert!(open(&key, &dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_modified_tag_err() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = seal(&key, plaintext).unwrap();
+ let dst_ciphertext_len = dst_ciphertext.len();
+ // Modify tag
+ dst_ciphertext[dst_ciphertext_len - 6] ^= 1;
+ assert!(open(&key, &dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_diff_secret_key_err() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+
+ let dst_ciphertext = seal(&key, plaintext).unwrap();
+ let bad_key = SecretKey::default();
+ assert!(open(&bad_key, &dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_secret_length_err() {
+ let key = SecretKey::generate(31).unwrap();
+ let plaintext = "Secret message".as_bytes();
+
+ assert!(seal(&key, plaintext).is_err());
+ assert!(open(&key, plaintext).is_err());
+ }
+ }
+
+ mod test_stream_seal_open {
+ use super::streaming::*;
+ use super::*;
+
+ #[test]
+ fn test_auth_enc_encryption_decryption() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let plaintext = "Secret message".as_bytes();
+
+ let dst_ciphertext = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ assert_eq!(dst_ciphertext.len(), plaintext.len() + 17);
+ let (dst_plaintext, tag) = opener.open_chunk(&dst_ciphertext).unwrap();
+ assert_eq!(plaintext, &dst_plaintext[..]);
+ assert_eq!(tag, StreamTag::Message);
+ }
+
+ #[test]
+ fn test_seal_chunk_plaintext_empty_ok() {
+ let key = SecretKey::default();
+ let (mut sealer, _) = StreamSealer::new(&key).unwrap();
+ let plaintext = "".as_bytes();
+
+ assert!(sealer.seal_chunk(plaintext, &StreamTag::Message).is_ok());
+ }
+
+ #[test]
+ fn test_open_chunk_less_than_abytes_err() {
+ let key = SecretKey::default();
+ let ciphertext = [0u8; ABYTES - 1];
+ let (_, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+
+ assert!(opener.open_chunk(&ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_open_chunk_abytes_exact_ok() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let ciphertext = sealer
+ .seal_chunk("".as_bytes(), &StreamTag::Message)
+ .unwrap();
+ let (pt, tag) = opener.open_chunk(&ciphertext).unwrap();
+
+ assert!(pt.is_empty());
+ assert_eq!(tag.as_byte(), 0u8);
+ }
+
+ #[test]
+ fn test_modified_tag_err() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ // Modify tag
+ dst_ciphertext[0] ^= 1;
+ assert!(opener.open_chunk(&dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_modified_ciphertext_err() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ // Modify ciphertext
+ dst_ciphertext[1] ^= 1;
+ assert!(opener.open_chunk(&dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_modified_mac_err() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let plaintext = "Secret message".as_bytes();
+
+ let mut dst_ciphertext = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ // Modify mac
+ let macpos = dst_ciphertext.len() - 1;
+ dst_ciphertext[macpos] ^= 1;
+ assert!(opener.open_chunk(&dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_diff_secret_key_err() {
+ let key = SecretKey::default();
+ let plaintext = "Secret message".as_bytes();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let bad_key = SecretKey::default();
+ let mut opener = StreamOpener::new(&bad_key, &nonce).unwrap();
+
+ let dst_ciphertext = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+
+ assert!(opener.open_chunk(&dst_ciphertext).is_err());
+ }
+
+ #[test]
+ fn test_secret_length_err() {
+ let key = SecretKey::generate(31).unwrap();
+ assert!(StreamSealer::new(&key).is_err());
+ assert!(StreamOpener::new(&key, &Nonce::generate()).is_err());
+ }
+
+ #[test]
+ fn same_input_generates_different_ciphertext() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let plaintext = "Secret message 1".as_bytes();
+ let cipher1 = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ let cipher2 = sealer.seal_chunk(plaintext, &StreamTag::Message).unwrap();
+ assert_ne!(cipher1, cipher2);
+
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let (dec1, tag1) = opener.open_chunk(&cipher1).unwrap();
+ let (dec2, tag2) = opener.open_chunk(&cipher2).unwrap();
+ assert_eq!(plaintext, &dec1[..]);
+ assert_eq!(plaintext, &dec2[..]);
+ assert_eq!(tag1, StreamTag::Message);
+ assert_eq!(tag2, StreamTag::Message);
+ }
+
+ #[test]
+ fn same_input_on_same_init_different_ct() {
+ // Two sealers initialized that encrypt the same plaintext
+ // should produce different ciphertexts because the nonce
+ // is randomly generated.
+ let key = SecretKey::default();
+ let (mut sealer_first, _) = StreamSealer::new(&key).unwrap();
+ let (mut sealer_second, _) = StreamSealer::new(&key).unwrap();
+ let plaintext = "Secret message 1".as_bytes();
+
+ let cipher1 = sealer_first
+ .seal_chunk(plaintext, &StreamTag::Message)
+ .unwrap();
+ let cipher2 = sealer_second
+ .seal_chunk(plaintext, &StreamTag::Message)
+ .unwrap();
+ assert_ne!(cipher1, cipher2);
+ }
+
+ #[test]
+ fn test_stream_seal_and_open() {
+ let key = SecretKey::default();
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let plaintext1 = "Secret message 1".as_bytes();
+ let plaintext2 = "Secret message 2".as_bytes();
+ let plaintext3 = "Secret message 3".as_bytes();
+ let cipher1 = sealer.seal_chunk(plaintext1, &StreamTag::Message).unwrap();
+ let cipher2 = sealer.seal_chunk(plaintext2, &StreamTag::Finish).unwrap();
+ let cipher3 = sealer.seal_chunk(plaintext3, &StreamTag::Message).unwrap();
+
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let (dec1, tag1) = opener.open_chunk(&cipher1).unwrap();
+ let (dec2, tag2) = opener.open_chunk(&cipher2).unwrap();
+ let (dec3, tag3) = opener.open_chunk(&cipher3).unwrap();
+ assert_eq!(plaintext1, &dec1[..]);
+ assert_eq!(plaintext2, &dec2[..]);
+ assert_eq!(plaintext3, &dec3[..]);
+ assert_eq!(tag1, StreamTag::Message);
+ assert_eq!(tag2, StreamTag::Finish);
+ assert_eq!(tag3, StreamTag::Message);
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_stream_seal_open_same_input(input: Vec<u8>) -> bool {
+ let key = SecretKey::default();
+
+ let (mut sealer, nonce) = StreamSealer::new(&key).unwrap();
+ let ct = sealer.seal_chunk(&input[..], &StreamTag::Message).unwrap();
+
+ let mut opener = StreamOpener::new(&key, &nonce).unwrap();
+ let (pt_decrypted, tag) = opener.open_chunk(&ct).unwrap();
+
+ input == pt_decrypted && tag == StreamTag::Message
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ // Sealing input, and then opening should always yield the same input.
+ fn prop_seal_open_same_input(input: Vec<u8>) -> bool {
+ let pt = if input.is_empty() {
+ vec![1u8; 10]
+ } else {
+ input
+ };
+
+ let sk = SecretKey::default();
+
+ let ct = seal(&sk, &pt).unwrap();
+ let pt_decrypted = open(&sk, &ct).unwrap();
+
+ pt == pt_decrypted
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ // Sealing input, modifying the tag and then opening should
+ // always fail due to authentication.
+ fn prop_fail_on_diff_key(input: Vec<u8>) -> bool {
+ let pt = if input.is_empty() {
+ vec![1u8; 10]
+ } else {
+ input
+ };
+
+ let sk = SecretKey::default();
+ let sk2 = SecretKey::default();
+ let ct = seal(&sk, &pt).unwrap();
+
+ open(&sk2, &ct).is_err()
+ }
+ }
+}
diff --git a/vendor/orion/src/high_level/auth.rs b/vendor/orion/src/high_level/auth.rs
new file mode 100644
index 0000000..7c61f9b
--- /dev/null
+++ b/vendor/orion/src/high_level/auth.rs
@@ -0,0 +1,212 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+//! Message authentication.
+//!
+//! # Use case:
+//! `orion::auth` can be used to ensure message integrity and authenticity by
+//! using a secret key.
+//!
+//! An example of this could be securing APIs by having a user of a given API
+//! sign their API request and having the API server verify these signed API
+//! requests.
+//!
+//! # About:
+//! - Uses BLAKE2b-256 in keyed mode.
+//!
+//! # Parameters:
+//! - `secret_key`: Secret key used to authenticate `data`.
+//! - `data`: Data to be authenticated.
+//! - `expected`: The expected authentication [`Tag`].
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The calculated [`Tag`] does not match the expected.
+//! - The [`SecretKey`] supplied is less than 32 bytes or greater than 64 bytes.
+//! - The expected [`Tag`] is not 32 bytes when verifying.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) bytes of data are authenticated.
+//!
+//! # Security:
+//! - The secret key should always be generated using a CSPRNG.
+//! [`SecretKey::default()`] can be used for
+//! this; it will generate a [`SecretKey`] of 32 bytes.
+//! - The required minimum length for a [`SecretKey`] is 32 bytes.
+//!
+//! # Example:
+//! ```rust
+//! use orion::auth;
+//!
+//! // There exists a shared key between the user and API server
+//! let key = auth::SecretKey::default();
+//!
+//! // User generates message and authentication tag
+//! let msg = "Some message.".as_bytes();
+//! let expected_tag = auth::authenticate(&key, msg)?;
+//!
+//! // API server verifies the authenticity of the message with the tag
+//! assert!(auth::authenticate_verify(&expected_tag, &key, &msg).is_ok());
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use super::hltypes::SecretKey;
+pub use crate::hazardous::mac::blake2b::Tag;
+use crate::{
+ errors::UnknownCryptoError,
+ hazardous::mac::blake2b::{self, Blake2b},
+};
+
+/// The Tag size (bytes) to be output by BLAKE2b in keyed mode.
+const BLAKE2B_TAG_SIZE: usize = 32;
+/// The minimum `SecretKey` size (bytes) to be used by BLAKE2b in keyed mode.
+const BLAKE2B_MIN_KEY_SIZE: usize = 32;
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Authenticate a message using BLAKE2b-256 in keyed mode.
+pub fn authenticate(secret_key: &SecretKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
+ if secret_key.len() < BLAKE2B_MIN_KEY_SIZE {
+ return Err(UnknownCryptoError);
+ }
+ let blake2b_secret_key = blake2b::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
+ let mut state = Blake2b::new(&blake2b_secret_key, BLAKE2B_TAG_SIZE)?;
+ state.update(data)?;
+ state.finalize()
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Authenticate and verify a message using BLAKE2b-256 in keyed mode.
+pub fn authenticate_verify(
+ expected: &Tag,
+ secret_key: &SecretKey,
+ data: &[u8],
+) -> Result<(), UnknownCryptoError> {
+ if secret_key.len() < BLAKE2B_MIN_KEY_SIZE || expected.len() != BLAKE2B_TAG_SIZE {
+ return Err(UnknownCryptoError);
+ }
+ let key = blake2b::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
+ Blake2b::verify(expected, &key, BLAKE2B_TAG_SIZE, data)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ mod test_auth_and_verify {
+ use super::*;
+ #[test]
+ fn test_authenticate_verify_bad_key() {
+ let sec_key_correct = SecretKey::generate(64).unwrap();
+ let sec_key_false = SecretKey::default();
+ let msg = "what do ya want for nothing?".as_bytes().to_vec();
+ let mac_bob = authenticate(&sec_key_correct, &msg).unwrap();
+
+ assert!(authenticate_verify(&mac_bob, &sec_key_correct, &msg).is_ok());
+ assert!(authenticate_verify(&mac_bob, &sec_key_false, &msg).is_err());
+ }
+
+ #[test]
+ fn test_authenticate_verify_bad_msg() {
+ let sec_key = SecretKey::generate(64).unwrap();
+ let msg = "what do ya want for nothing?".as_bytes().to_vec();
+ let mac_bob = authenticate(&sec_key, &msg).unwrap();
+
+ assert!(authenticate_verify(&mac_bob, &sec_key, &msg).is_ok());
+ assert!(authenticate_verify(&mac_bob, &sec_key, b"bad msg").is_err());
+ }
+
+ #[test]
+ fn test_authenticate_key_too_small() {
+ let sec_key = SecretKey::generate(31).unwrap();
+ let msg = "what do ya want for nothing?".as_bytes().to_vec();
+
+ assert!(authenticate(&sec_key, &msg).is_err());
+ }
+
+ #[test]
+ fn test_authenticate_verify_key_too_small() {
+ let sec_key = SecretKey::generate(31).unwrap();
+ let msg = "what do ya want for nothing?".as_bytes().to_vec();
+ let mac = Tag::from_slice(&[0u8; 32][..]).unwrap();
+
+ assert!(authenticate_verify(&mac, &sec_key, &msg).is_err());
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Authentication and verifying that tag with the same parameters
+ /// should always be true.
+ fn prop_authenticate_verify(input: Vec<u8>) -> bool {
+ let sk = SecretKey::default();
+ let tag = authenticate(&sk, &input[..]).unwrap();
+ authenticate_verify(&tag, &sk, &input[..]).is_ok()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Authentication and verifying that tag with a different key should
+ /// never be true.
+ fn prop_verify_fail_diff_key(input: Vec<u8>) -> bool {
+ let sk = SecretKey::default();
+ let sk2 = SecretKey::default();
+ let tag = authenticate(&sk, &input[..]).unwrap();
+
+ authenticate_verify(&tag, &sk2, &input[..]).is_err()
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Authentication and verifying that tag with different input should
+ /// never be true.
+ fn prop_verify_fail_diff_input(input: Vec<u8>) -> bool {
+ let sk = SecretKey::default();
+ let tag = authenticate(&sk, &input[..]).unwrap();
+
+ authenticate_verify(&tag, &sk, b"Completely wrong input").is_err()
+ }
+
+ use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_KEYSIZE;
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Verify the bounds of 32..=64 (inclusive) for the `SecretKey` used
+ /// in `authenticate/authenticate_verify`.
+ fn prop_authenticate_key_size(input: Vec<u8>) -> bool {
+ let sec_key_res = SecretKey::from_slice(&input);
+ if input.is_empty() || input.len() >= u32::MAX as usize {
+ return sec_key_res.is_err();
+ }
+ let sec_key = sec_key_res.unwrap();
+ let msg = "what do ya want for nothing?".as_bytes().to_vec();
+ let auth_res = authenticate(&sec_key, &msg);
+ if input.len() >= BLAKE2B_MIN_KEY_SIZE && input.len() <= BLAKE2B_KEYSIZE {
+ auth_res.is_ok()
+ } else {
+ auth_res.is_err()
+ }
+ }
+}
diff --git a/vendor/orion/src/high_level/hash.rs b/vendor/orion/src/high_level/hash.rs
new file mode 100644
index 0000000..78b4bda
--- /dev/null
+++ b/vendor/orion/src/high_level/hash.rs
@@ -0,0 +1,134 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+//! Hashing.
+//!
+//! # Use case:
+//! `orion::hash` can be used to hash some given data.
+//!
+//! An example of this could be using hashes of files to ensure integrity.
+//! Meaning, checking if a file has been modified since the time the hash was
+//! recorded.
+//!
+//! If you are looking for a keyed hash, please see the [`orion::auth`](super::auth) module.
+//!
+//! # About:
+//! - Uses BLAKE2b with an output size of 32 bytes (i.e BLAKE2b-256).
+//!
+//! # Parameters:
+//! - `data`: The data to be hashed.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than 2*(2^64-1) bytes of data are hashed.
+//!
+//! # Security:
+//! - This interface does not support supplying BLAKE2b with a secret key, and
+//! the hashes retrieved
+//! from using `orion::hash` are therefore not suitable as MACs.
+//! - BLAKE2b is not suitable for password hashing. See [`orion::pwhash`](super::pwhash)
+//! instead.
+//!
+//! # Examples
+//!
+//! ## Hashing in-memory data
+//! ```rust
+//! use orion::hash::{digest, Digest};
+//!
+//! let hash: Digest = digest(b"Some data")?;
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//!
+//! ## Hashing data from an arbitrary reader
+//! ```rust
+//! use orion::hash::{digest_from_reader, Digest};
+//!
+//! // `reader` could instead be `File::open("file.txt")?`
+//! let reader = std::io::Cursor::new(b"some data");
+//! let hash: Digest = digest_from_reader(reader)?;
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use crate::hazardous::hash::blake2::blake2b::Digest;
+use crate::{errors::UnknownCryptoError, hazardous::hash::blake2::blake2b};
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Hashing using BLAKE2b-256.
+pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ blake2b::Hasher::Blake2b256.digest(data)
+}
+
+/// Hash data from a [`Read`](std::io::Read)` type using BLAKE2b-256.
+///
+/// See the [module-level docs](crate::hash) for an example of how to use this function.
+/// Internally calls [`std::io::copy`]() to move data from the reader into the Blake2b writer.
+/// Note that the [`std::io::copy`]() function buffers reads, so passing in a
+/// [`BufReader`](std::io::BufReader) may be unnecessary.
+///
+/// For lower-level control over reads, writes, buffer sizes, *etc.*, consider using the
+/// [`Blake2b`](crate::hazardous::hash::blake2::blake2b::Blake2b) type and its
+/// [`Write`](std::io::Write) implementation directly. See `Blake2b`'s `Write` implementation
+/// and/or its `Write` documentation for an example.
+///
+/// ## 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.
+///
+/// Note that if an error is returned, data may still have been consumed from the given reader.
+#[cfg(feature = "safe_api")]
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+pub fn digest_from_reader(mut reader: impl std::io::Read) -> Result<Digest, UnknownCryptoError> {
+ let mut hasher = blake2b::Blake2b::new(32)?;
+ std::io::copy(&mut reader, &mut hasher).map_err(|_| UnknownCryptoError)?;
+ hasher.finalize()
+}
+
+// Testing public functions in the module.
+#[cfg(feature = "safe_api")]
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[quickcheck]
+ /// Hashing twice with same input should always produce same output.
+ fn prop_digest_same_result(input: Vec<u8>) -> bool {
+ digest(&input[..]).unwrap() == digest(&input[..]).unwrap()
+ }
+
+ #[quickcheck]
+ /// Hashing all input should be the same as wrapping it in a
+ /// cursor and using digest_from_reader.
+ fn prop_digest_same_as_digest_from_reader(input: Vec<u8>) -> bool {
+ let digest_a = digest_from_reader(std::io::Cursor::new(&input)).unwrap();
+ let digest_b = digest(&input).unwrap();
+ digest_a == digest_b
+ }
+
+ #[quickcheck]
+ /// Hashing twice with different input should never produce same output.
+ fn prop_digest_diff_result(input: Vec<u8>) -> bool {
+ digest(&input[..]).unwrap() != digest(b"Completely wrong input").unwrap()
+ }
+}
diff --git a/vendor/orion/src/high_level/hltypes.rs b/vendor/orion/src/high_level/hltypes.rs
new file mode 100644
index 0000000..419cb22
--- /dev/null
+++ b/vendor/orion/src/high_level/hltypes.rs
@@ -0,0 +1,76 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+/// These are the different types used by the high-level interface. They are not
+/// used in `hazardous`.
+use crate::errors::UnknownCryptoError;
+
+construct_secret_key_variable_size! {
+ /// A type to represent a secret key.
+ ///
+ /// As default it will randomly generate a `SecretKey` of 32 bytes.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `length` is 0.
+ /// - `length` is not less than [`isize::MAX`].
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (SecretKey, test_secret_key, 32)
+}
+
+construct_salt_variable_size! {
+ /// A type to represent the `Salt` that Argon2i uses during key derivation.
+ ///
+ /// As default it will randomly generate a `Salt` of 16 bytes.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `length` is 0.
+ /// - `length` is not less than [`isize::MAX`].
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Salt, test_salt, 16)
+}
+
+construct_secret_key_variable_size! {
+ /// A type to represent the `Password` that Argon2i hashes and uses for key derivation.
+ ///
+ /// As default it will randomly generate a `Password` of 32 bytes.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is empty.
+ /// - `length` is 0.
+ /// - `length` is not less than [`isize::MAX`].
+ ///
+ /// # Panics:
+ /// A panic will occur if:
+ /// - Failure to generate random bytes securely.
+ (Password, test_password, 32)
+}
diff --git a/vendor/orion/src/high_level/kdf.rs b/vendor/orion/src/high_level/kdf.rs
new file mode 100644
index 0000000..87f0192
--- /dev/null
+++ b/vendor/orion/src/high_level/kdf.rs
@@ -0,0 +1,222 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+//! Key derivation.
+//!
+//! # Use case:
+//! `orion::kdf` can be used to derive higher-entropy keys from low-entropy
+//! keys. Also known as key stretching.
+//!
+//! An example of this could be deriving a key from a user-submitted password
+//! and using this derived key in disk encryption.
+//!
+//! # About:
+//! - Uses Argon2i.
+//!
+//! # Note:
+//! This implementation only supports a single thread/lane.
+//!
+//! # Parameters:
+//! - `password`: The low-entropy input key to be used in key derivation.
+//! - `salt`: The salt used for the key derivation.
+//! - `iterations`: Iterations cost parameter for Argon2i.
+//! - `memory`: Memory (in kibibytes (KiB)) cost parameter for Argon2i.
+//! - `length`: The desired length of the derived key.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - `iterations` is less than 3.
+//! - `length` is less than 4.
+//! - `memory` is less than 8.
+//! - The length of the `password` is greater than [`isize::MAX`].
+//! - The length of the `salt` is greater than [`isize::MAX`] or less than `8`.
+//!
+//! # Security:
+//! - Choosing the correct cost parameters is important for security. Please refer to
+//! [libsodium's docs] for a description of how to do this.
+//! - The salt should always be generated using a CSPRNG. [`Salt::default()`]
+//! can be used for this, it will generate a [`Salt`] of 16 bytes.
+//! - The recommended minimum size for a salt is 16 bytes.
+//! - The recommended minimum size for a derived key is 16 bytes.
+//!
+//! If the concrete cost parameters needed are unclear, please refer to [OWASP] for recommended minimum values.
+//!
+//! # Example:
+//! ```rust
+//! use orion::kdf;
+//!
+//! let user_password = kdf::Password::from_slice(b"User password")?;
+//! let salt = kdf::Salt::default();
+//!
+//! let derived_key = kdf::derive_key(&user_password, &salt, 3, 1<<16, 32)?;
+//!
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [libsodium's docs]: https://download.libsodium.org/doc/password_hashing/default_phf#guidelines-for-choosing-the-parameters
+//! [OWASP]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use super::hltypes::{Password, Salt, SecretKey};
+use crate::{errors::UnknownCryptoError, hazardous::kdf::argon2i, pwhash::MIN_ITERATIONS};
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Derive a key using Argon2i.
+pub fn derive_key(
+ password: &Password,
+ salt: &Salt,
+ iterations: u32,
+ memory: u32,
+ length: u32,
+) -> Result<SecretKey, UnknownCryptoError> {
+ if iterations < MIN_ITERATIONS {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut dk = SecretKey::from_slice(&vec![0u8; length as usize])?;
+
+ argon2i::derive_key(
+ password.unprotected_as_bytes(),
+ salt.as_ref(),
+ iterations,
+ memory,
+ None,
+ None,
+ &mut dk.value,
+ )?;
+
+ Ok(dk)
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ mod test_derive_key_and_verify {
+ use super::*;
+
+ #[test]
+ fn test_derive_key() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 16]).unwrap();
+ let dk_first = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_second = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+
+ assert_eq!(dk_first, dk_second);
+ }
+
+ #[test]
+ fn test_derive_key_err_diff_iter() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+ let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_diff_iter = derive_key(&password, &salt, 4, 1024, 32).unwrap();
+
+ assert_ne!(dk, dk_diff_iter);
+ }
+
+ #[test]
+ fn test_derive_key_err_diff_mem() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+ let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_diff_mem = derive_key(&password, &salt, 3, 512, 32).unwrap();
+
+ assert_ne!(dk, dk_diff_mem);
+ }
+
+ #[test]
+ fn test_derive_key_err_diff_salt() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+ let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_diff_salt = derive_key(
+ &password,
+ &Salt::from_slice(&[1u8; 64]).unwrap(),
+ 3,
+ 1024,
+ 32,
+ )
+ .unwrap();
+
+ assert_ne!(dk, dk_diff_salt);
+ }
+
+ #[test]
+ fn test_derive_key_err_diff_len() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+ let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_diff_len = derive_key(&password, &salt, 3, 1024, 64).unwrap();
+
+ assert_ne!(dk, dk_diff_len);
+ }
+
+ #[test]
+ fn test_derive_key_err_diff_pass() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+ let dk = derive_key(&password, &salt, 3, 1024, 32).unwrap();
+ let dk_diff_pass = derive_key(
+ &Password::from_slice(&[1u8; 64]).unwrap(),
+ &salt,
+ 3,
+ 1024,
+ 32,
+ )
+ .unwrap();
+
+ assert_ne!(dk, dk_diff_pass);
+ }
+
+ #[test]
+ fn test_derive_key_bad_length() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 64]).unwrap();
+
+ assert!(derive_key(&password, &salt, 3, 1024, 3).is_err());
+ assert!(derive_key(&password, &salt, 3, 1024, 4).is_ok());
+ assert!(derive_key(&password, &salt, 3, 1024, 5).is_ok());
+ }
+
+ #[test]
+ fn test_derive_key_bad_iter() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 16]).unwrap();
+
+ assert!(derive_key(&password, &salt, 2, 1024, 32).is_err());
+ assert!(derive_key(&password, &salt, 3, 1024, 32).is_ok());
+ assert!(derive_key(&password, &salt, 4, 1024, 32).is_ok());
+ }
+
+ #[test]
+ fn test_derive_key_bad_mem() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let salt = Salt::from_slice(&[0u8; 16]).unwrap();
+
+ assert!(derive_key(&password, &salt, 3, 7, 32).is_err());
+ assert!(derive_key(&password, &salt, 3, 8, 32).is_ok());
+ assert!(derive_key(&password, &salt, 3, 9, 32).is_ok());
+ }
+ }
+}
diff --git a/vendor/orion/src/high_level/kex.rs b/vendor/orion/src/high_level/kex.rs
new file mode 100644
index 0000000..787f514
--- /dev/null
+++ b/vendor/orion/src/high_level/kex.rs
@@ -0,0 +1,539 @@
+// MIT License
+
+// Copyright (c) 2021-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.
+
+//! Ephemeral key exchange.
+//!
+//! # Use case:
+//! `orion::kex` can be used to establish a pair of shared keys between two parties.
+//!
+//! # About:
+//! - Both [`EphemeralClientSession`] and [`EphemeralServerSession`] consume `self` when shared keys
+//! are being established. You can therefore never use the same private key for more than a single
+//! key exchange.
+//!
+//! This implementation is based on and compatible with the
+//! [key exchange API](https://doc.libsodium.org/key_exchange) of libsodium.
+//!
+//! # Parameters:
+//! - `server_public_key`: The server's public key used to establish the client's shared session keys.
+//! - `client_public_key`: The client's public key used to establish the server's shared session keys.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - If the key exchange results in an all-zero output.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - Failure to generate random bytes securely.
+//!
+//! # Security:
+//! - The API is designed to be ephemeral and a [`PrivateKey`] should not be used more than once.
+//!
+//! # Example:
+//! ```rust
+//! use orion::kex::*;
+//! use orion::aead;
+//!
+//! /// The server initializes their ephemeral session keys
+//! let session_server = EphemeralServerSession::new()?;
+//! let server_public_key = session_server.public_key();
+//!
+//! /// The client initializes their ephemeral session keys
+//! let session_client = EphemeralClientSession::new()?;
+//! let client_public_key = session_client.public_key().clone();
+//!
+//! let client_keys: SessionKeys = session_client
+//! .establish_with_server(server_public_key)?;
+//!
+//! let server_keys: SessionKeys = session_server
+//! .establish_with_client(&client_public_key)?;
+//!
+//! assert_eq!(client_keys.receiving(), server_keys.transport());
+//! assert_eq!(client_keys.transport(), server_keys.receiving());
+//!
+//! // The client can now "send" encrypted data to the server and vice versa
+//!
+//! // Client sends an encrypted message which the server decrypts:
+//! let client_msg = aead::seal(client_keys.transport(), b"Hello, server!")?;
+//! assert_eq!(aead::open(server_keys.receiving(), &client_msg)?, b"Hello, server!");
+//!
+//! // Server responds and client decrypts the received message:
+//! let server_msg = aead::seal(server_keys.transport(), b"Hello, client!")?;
+//! assert_eq!(aead::open(client_keys.receiving(), &server_msg)?, b"Hello, client!");
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use super::hltypes::SecretKey;
+pub use crate::hazardous::ecc::x25519::PrivateKey;
+pub use crate::hazardous::ecc::x25519::PublicKey;
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::ecc::x25519;
+use crate::hazardous::hash::blake2::blake2b::{Blake2b, Digest};
+use core::convert::TryFrom;
+
+#[derive(Debug, PartialEq)]
+/// A key pair used to establish shared keys for a single session.
+pub struct EphemeralClientSession {
+ private_key: PrivateKey,
+ public_key: PublicKey,
+}
+
+impl EphemeralClientSession {
+ /// Generate a new random key pair.
+ pub fn new() -> Result<Self, UnknownCryptoError> {
+ let privkey = PrivateKey::generate();
+ let pubkey: PublicKey = PublicKey::try_from(&privkey)?;
+
+ Ok(Self {
+ private_key: privkey,
+ public_key: pubkey,
+ })
+ }
+
+ /// Get a reference to the [`PublicKey`].
+ pub fn public_key(&self) -> &PublicKey {
+ &self.public_key
+ }
+
+ /// Get a reference to the [`PrivateKey`].
+ pub fn private_key(&self) -> &PrivateKey {
+ &self.private_key
+ }
+
+ /// Establish session keys with a server. This moves `self` to ensure that the keys
+ /// generated with [`Self::new()`] are only used for this key exchange, thus remaining ephemeral.
+ pub fn establish_with_server(
+ self,
+ server_public_key: &PublicKey,
+ ) -> Result<SessionKeys, UnknownCryptoError> {
+ let q = x25519::key_agreement(&self.private_key, server_public_key)?;
+ let keys = establish_session_keys(&q, &self.public_key, server_public_key)?;
+
+ Ok(SessionKeys {
+ rx: SecretKey::from_slice(&keys.as_ref()[..32])?,
+ tx: SecretKey::from_slice(&keys.as_ref()[32..])?,
+ })
+ }
+}
+
+#[derive(Debug, PartialEq)]
+/// A key pair used to establish shared keys for a single session.
+pub struct EphemeralServerSession {
+ private_key: PrivateKey,
+ public_key: PublicKey,
+}
+
+impl EphemeralServerSession {
+ /// Generate a new random key pair.
+ pub fn new() -> Result<Self, UnknownCryptoError> {
+ let privkey = PrivateKey::generate();
+ let pubkey: PublicKey = PublicKey::try_from(&privkey)?;
+
+ Ok(Self {
+ private_key: privkey,
+ public_key: pubkey,
+ })
+ }
+
+ /// Get a reference to the [`PublicKey`].
+ pub fn public_key(&self) -> &PublicKey {
+ &self.public_key
+ }
+
+ /// Get a reference to the [`PrivateKey`].
+ pub fn private_key(&self) -> &PrivateKey {
+ &self.private_key
+ }
+
+ /// Establish session keys with a client. This moves `self` to ensure that the keys
+ /// generated with [`Self::new()`] are only used for this key exchange, thus remaining ephemeral.
+ pub fn establish_with_client(
+ self,
+ client_public_key: &PublicKey,
+ ) -> Result<SessionKeys, UnknownCryptoError> {
+ let q = x25519::key_agreement(&self.private_key, client_public_key)?;
+ let keys = establish_session_keys(&q, client_public_key, &self.public_key)?;
+
+ Ok(SessionKeys {
+ rx: SecretKey::from_slice(&keys.as_ref()[32..])?,
+ tx: SecretKey::from_slice(&keys.as_ref()[..32])?,
+ })
+ }
+}
+
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Debug, PartialEq)]
+/// A set of shared secrets for either transmitting to this entity or send to another party.
+pub struct SessionKeys {
+ rx: SecretKey,
+ tx: SecretKey,
+}
+
+impl SessionKeys {
+ /// Get the shared secret intended to be used for receiving data from the other party.
+ pub fn receiving(&self) -> &SecretKey {
+ &self.rx
+ }
+
+ /// Get the shared secret intended to be used for transporting data to the other party.
+ pub fn transport(&self) -> &SecretKey {
+ &self.tx
+ }
+}
+
+/// Using BLAKE2b, derive two shared secret from a scalarmult computation.
+fn establish_session_keys(
+ shared_secret: &x25519::SharedKey,
+ client_pk: &PublicKey,
+ server_pk: &PublicKey,
+) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Blake2b::new(64)?;
+ ctx.update(shared_secret.unprotected_as_bytes())?;
+ ctx.update(&client_pk.to_bytes())?;
+ ctx.update(&server_pk.to_bytes())?;
+ ctx.finalize()
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_basic_key_exchange() {
+ let session_server = EphemeralServerSession::new().unwrap();
+ let server_public_key = session_server.public_key();
+
+ let session_client = EphemeralClientSession::new().unwrap();
+ let client_public_key = session_client.public_key().clone();
+
+ assert_ne!(session_client.private_key(), session_server.private_key());
+
+ let client = session_client
+ .establish_with_server(server_public_key)
+ .unwrap();
+ let server = session_server
+ .establish_with_client(&client_public_key)
+ .unwrap();
+
+ assert_eq!(client.receiving(), server.transport());
+ assert_eq!(client.transport(), server.receiving());
+
+ assert_ne!(client.receiving(), server.receiving());
+ assert_ne!(client.transport(), server.transport());
+ }
+
+ #[test]
+ fn test_error_on_low_order_public() {
+ // Taken from: https://github.com/jedisct1/libsodium/blob/master/test/default/kx.c
+ let low_order_public: [u8; 32] = [
+ 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f,
+ 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16,
+ 0x5f, 0x49, 0xb8, 0x00,
+ ];
+ let server_low_order_pk = PublicKey::from_slice(&low_order_public).unwrap();
+
+ let session_client = EphemeralClientSession::new().unwrap();
+ assert!(session_client
+ .establish_with_server(&server_low_order_pk)
+ .is_err());
+ }
+
+ // The following are tests generated with sodiumoxide to test basic compatability with libsodium API.
+ #[test]
+ fn libsodium_compat_test_1() {
+ let client_pk = "299283d8713b7d430376cb257e13cd5ad1a6e5ebe6135417f4bb3b45bf42f31a";
+ let client_sk = "e026533c3efa096ce9c4d77ad7c3d6948af2f9ef628b88430228ca0465ec35b9";
+ let server_pk = "1716d0c006e5f3c2240b2ccec9357dbd04030f51d3e584923e70823cd6fcab1c";
+ let server_sk = "55a94da5003d7807850938e84a5082d3deba8e5bbf5c50f814e8160270c165b4";
+ let client_rx = "37830d33c5de06fbe246db5803ed70284fe9ab78bc6b896a3db3a9b8db50418b";
+ let client_tx = "201d1bb45d4b9164f269d59cc00ba1a49c1924c27485bb6e5cc77ea4cc38ec7e";
+ let server_rx = "201d1bb45d4b9164f269d59cc00ba1a49c1924c27485bb6e5cc77ea4cc38ec7e";
+ let server_tx = "37830d33c5de06fbe246db5803ed70284fe9ab78bc6b896a3db3a9b8db50418b";
+
+ let client_public = PublicKey::from_slice(&hex::decode(client_pk).unwrap()).unwrap();
+ let client_secret = PrivateKey::from_slice(&hex::decode(client_sk).unwrap()).unwrap();
+ let server_public = PublicKey::from_slice(&hex::decode(server_pk).unwrap()).unwrap();
+ let server_secret = PrivateKey::from_slice(&hex::decode(server_sk).unwrap()).unwrap();
+
+ let client_recv = SecretKey::from_slice(&hex::decode(client_rx).unwrap()).unwrap();
+ let client_trans = SecretKey::from_slice(&hex::decode(client_tx).unwrap()).unwrap();
+ let server_recv = SecretKey::from_slice(&hex::decode(server_rx).unwrap()).unwrap();
+ let server_trans = SecretKey::from_slice(&hex::decode(server_tx).unwrap()).unwrap();
+
+ let session_client = EphemeralClientSession {
+ private_key: client_secret,
+ public_key: client_public.clone(),
+ };
+
+ let session_server = EphemeralServerSession {
+ private_key: server_secret,
+ public_key: server_public.clone(),
+ };
+
+ let expected_client_shared = SessionKeys {
+ rx: client_recv,
+ tx: client_trans,
+ };
+
+ let expected_server_shared = SessionKeys {
+ rx: server_recv,
+ tx: server_trans,
+ };
+
+ assert_eq!(
+ session_client
+ .establish_with_server(&server_public)
+ .unwrap(),
+ expected_client_shared
+ );
+ assert_eq!(
+ session_server
+ .establish_with_client(&client_public)
+ .unwrap(),
+ expected_server_shared
+ );
+ }
+
+ #[test]
+ fn libsodium_compat_test_2() {
+ let client_pk = "31f8eed74832d31b106702ecdf464a54e9fb9514d241473c5b51deb0d126893a";
+ let client_sk = "dcb760f46480ea5c2647e8dcbdc30fff8da6811712b4d5c7144aca1b72d6adb7";
+ let server_pk = "ccf7a7d5d2973f517a2276f0ca6c15da3c90a85db12e3ec171c4441c2b48f15d";
+ let server_sk = "e73ebfde3907296e5452e1f22ea1a85d4f3cdbf3ff9f099d45a0853d3b87d64f";
+ let client_rx = "25789992d2eac8bc0e1c3322d9b8e26050064ea3cead77ca2cf36966dea54186";
+ let client_tx = "f69cf60f763fb2a9c47dc1b3237983ef79cecd26205c68f9c16e91db6c8f3f18";
+ let server_rx = "f69cf60f763fb2a9c47dc1b3237983ef79cecd26205c68f9c16e91db6c8f3f18";
+ let server_tx = "25789992d2eac8bc0e1c3322d9b8e26050064ea3cead77ca2cf36966dea54186";
+
+ let client_public = PublicKey::from_slice(&hex::decode(client_pk).unwrap()).unwrap();
+ let client_secret = PrivateKey::from_slice(&hex::decode(client_sk).unwrap()).unwrap();
+ let server_public = PublicKey::from_slice(&hex::decode(server_pk).unwrap()).unwrap();
+ let server_secret = PrivateKey::from_slice(&hex::decode(server_sk).unwrap()).unwrap();
+
+ let client_recv = SecretKey::from_slice(&hex::decode(client_rx).unwrap()).unwrap();
+ let client_trans = SecretKey::from_slice(&hex::decode(client_tx).unwrap()).unwrap();
+ let server_recv = SecretKey::from_slice(&hex::decode(server_rx).unwrap()).unwrap();
+ let server_trans = SecretKey::from_slice(&hex::decode(server_tx).unwrap()).unwrap();
+
+ let session_client = EphemeralClientSession {
+ private_key: client_secret,
+ public_key: client_public.clone(),
+ };
+
+ let session_server = EphemeralServerSession {
+ private_key: server_secret,
+ public_key: server_public.clone(),
+ };
+
+ let expected_client_shared = SessionKeys {
+ rx: client_recv,
+ tx: client_trans,
+ };
+
+ let expected_server_shared = SessionKeys {
+ rx: server_recv,
+ tx: server_trans,
+ };
+
+ assert_eq!(
+ session_client
+ .establish_with_server(&server_public)
+ .unwrap(),
+ expected_client_shared
+ );
+ assert_eq!(
+ session_server
+ .establish_with_client(&client_public)
+ .unwrap(),
+ expected_server_shared
+ );
+ }
+
+ #[test]
+ fn libsodium_compat_test_3() {
+ let client_pk = "57f57eda618289c8f55dee0a8069405d9874684282b8380878b180719055333a";
+ let client_sk = "7d613b91a1cf6a34787362229cfaf6d50613e276a20ef59eea7f02d9236cd9f7";
+ let server_pk = "997f12b2ef5ba2c639c4dc39f159ce5169b60b9a3b65365f958cfb822e37b513";
+ let server_sk = "c3156f11e0cc31ffb92dfd5e780738011cfe80cc4184f5a3f190892528a9bac3";
+ let client_rx = "89f90402d56d5e184b1682c21583e695560e0ab54459d09a51a596a8d33293da";
+ let client_tx = "547c1f1be7abe8d10bf92fb19f79edd2139441b4faa54976b5db90a50b7244c4";
+ let server_rx = "547c1f1be7abe8d10bf92fb19f79edd2139441b4faa54976b5db90a50b7244c4";
+ let server_tx = "89f90402d56d5e184b1682c21583e695560e0ab54459d09a51a596a8d33293da";
+
+ let client_public = PublicKey::from_slice(&hex::decode(client_pk).unwrap()).unwrap();
+ let client_secret = PrivateKey::from_slice(&hex::decode(client_sk).unwrap()).unwrap();
+ let server_public = PublicKey::from_slice(&hex::decode(server_pk).unwrap()).unwrap();
+ let server_secret = PrivateKey::from_slice(&hex::decode(server_sk).unwrap()).unwrap();
+
+ let client_recv = SecretKey::from_slice(&hex::decode(client_rx).unwrap()).unwrap();
+ let client_trans = SecretKey::from_slice(&hex::decode(client_tx).unwrap()).unwrap();
+ let server_recv = SecretKey::from_slice(&hex::decode(server_rx).unwrap()).unwrap();
+ let server_trans = SecretKey::from_slice(&hex::decode(server_tx).unwrap()).unwrap();
+
+ let session_client = EphemeralClientSession {
+ private_key: client_secret,
+ public_key: client_public.clone(),
+ };
+
+ let session_server = EphemeralServerSession {
+ private_key: server_secret,
+ public_key: server_public.clone(),
+ };
+
+ let expected_client_shared = SessionKeys {
+ rx: client_recv,
+ tx: client_trans,
+ };
+
+ let expected_server_shared = SessionKeys {
+ rx: server_recv,
+ tx: server_trans,
+ };
+
+ assert_eq!(
+ session_client
+ .establish_with_server(&server_public)
+ .unwrap(),
+ expected_client_shared
+ );
+ assert_eq!(
+ session_server
+ .establish_with_client(&client_public)
+ .unwrap(),
+ expected_server_shared
+ );
+ }
+
+ #[test]
+ fn libsodium_compat_test_4() {
+ let client_pk = "2df30ccfd5eb6cb1ae5428dd06129a22fe8eac2b8b0cfcc1876bbaeb2b515703";
+ let client_sk = "52b73937f462130c82c427d68b26b689d3c020169909fea3043882654fa8e1a3";
+ let server_pk = "ef09a7379139627b2a13d0376f7fea1e4e2c27859757b74282b4368d2701de1c";
+ let server_sk = "384de0b04d358ef0a99cec457507b83a9fcff0c9a2875d1fc771c1b203eb90f5";
+ let client_rx = "738d3ff37e8b5d58daf888111359693042508617ef088c2048c0d87bc002ca38";
+ let client_tx = "fd1ab19e5c6ac0c5508ba129ded170a25c04f6f1ab9ccc3e66cd73988ade8471";
+ let server_rx = "fd1ab19e5c6ac0c5508ba129ded170a25c04f6f1ab9ccc3e66cd73988ade8471";
+ let server_tx = "738d3ff37e8b5d58daf888111359693042508617ef088c2048c0d87bc002ca38";
+
+ let client_public = PublicKey::from_slice(&hex::decode(client_pk).unwrap()).unwrap();
+ let client_secret = PrivateKey::from_slice(&hex::decode(client_sk).unwrap()).unwrap();
+ let server_public = PublicKey::from_slice(&hex::decode(server_pk).unwrap()).unwrap();
+ let server_secret = PrivateKey::from_slice(&hex::decode(server_sk).unwrap()).unwrap();
+
+ let client_recv = SecretKey::from_slice(&hex::decode(client_rx).unwrap()).unwrap();
+ let client_trans = SecretKey::from_slice(&hex::decode(client_tx).unwrap()).unwrap();
+ let server_recv = SecretKey::from_slice(&hex::decode(server_rx).unwrap()).unwrap();
+ let server_trans = SecretKey::from_slice(&hex::decode(server_tx).unwrap()).unwrap();
+
+ let session_client = EphemeralClientSession {
+ private_key: client_secret,
+ public_key: client_public.clone(),
+ };
+
+ let session_server = EphemeralServerSession {
+ private_key: server_secret,
+ public_key: server_public.clone(),
+ };
+
+ let expected_client_shared = SessionKeys {
+ rx: client_recv,
+ tx: client_trans,
+ };
+
+ let expected_server_shared = SessionKeys {
+ rx: server_recv,
+ tx: server_trans,
+ };
+
+ assert_eq!(
+ session_client
+ .establish_with_server(&server_public)
+ .unwrap(),
+ expected_client_shared
+ );
+ assert_eq!(
+ session_server
+ .establish_with_client(&client_public)
+ .unwrap(),
+ expected_server_shared
+ );
+ }
+
+ #[test]
+ fn libsodium_compat_test_5() {
+ let client_pk = "c4be3dfb50430e57313b6eeafc40e9b432120c4dd3d34ca6dedae1391b898c43";
+ let client_sk = "23702adbbab5918b682b2a1b2b27c634865b3dcf51ed81e287da30edd4f7ef39";
+ let server_pk = "a241a5a8c16e3731ddc8d3e5e5890f85b9de2c87095be3239379b3c62f73f949";
+ let server_sk = "530493dddf346371ce562557d5b0ff40ddbff038cf6a20187c16510ce57cc93f";
+ let client_rx = "8fa8dfc483108262b058b60b11e2f9b5b47287061bde785827afafb102a09ec7";
+ let client_tx = "a01332e4cb85b2bfac65f86936f27058b339889442c13eee06414bfb2d68c58b";
+ let server_rx = "a01332e4cb85b2bfac65f86936f27058b339889442c13eee06414bfb2d68c58b";
+ let server_tx = "8fa8dfc483108262b058b60b11e2f9b5b47287061bde785827afafb102a09ec7";
+
+ let client_public = PublicKey::from_slice(&hex::decode(client_pk).unwrap()).unwrap();
+ let client_secret = PrivateKey::from_slice(&hex::decode(client_sk).unwrap()).unwrap();
+ let server_public = PublicKey::from_slice(&hex::decode(server_pk).unwrap()).unwrap();
+ let server_secret = PrivateKey::from_slice(&hex::decode(server_sk).unwrap()).unwrap();
+
+ let client_recv = SecretKey::from_slice(&hex::decode(client_rx).unwrap()).unwrap();
+ let client_trans = SecretKey::from_slice(&hex::decode(client_tx).unwrap()).unwrap();
+ let server_recv = SecretKey::from_slice(&hex::decode(server_rx).unwrap()).unwrap();
+ let server_trans = SecretKey::from_slice(&hex::decode(server_tx).unwrap()).unwrap();
+
+ let session_client = EphemeralClientSession {
+ private_key: client_secret,
+ public_key: client_public.clone(),
+ };
+
+ let session_server = EphemeralServerSession {
+ private_key: server_secret,
+ public_key: server_public.clone(),
+ };
+
+ let expected_client_shared = SessionKeys {
+ rx: client_recv,
+ tx: client_trans,
+ };
+
+ let expected_server_shared = SessionKeys {
+ rx: server_recv,
+ tx: server_trans,
+ };
+
+ assert_eq!(
+ session_client
+ .establish_with_server(&server_public)
+ .unwrap(),
+ expected_client_shared
+ );
+ assert_eq!(
+ session_server
+ .establish_with_client(&client_public)
+ .unwrap(),
+ expected_server_shared
+ );
+ }
+}
diff --git a/vendor/orion/src/high_level/mod.rs b/vendor/orion/src/high_level/mod.rs
new file mode 100644
index 0000000..25080e8
--- /dev/null
+++ b/vendor/orion/src/high_level/mod.rs
@@ -0,0 +1,29 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+pub mod aead;
+pub mod auth;
+pub mod hash;
+mod hltypes;
+pub mod kdf;
+pub mod kex;
+pub mod pwhash;
diff --git a/vendor/orion/src/high_level/pwhash.rs b/vendor/orion/src/high_level/pwhash.rs
new file mode 100644
index 0000000..3daee39
--- /dev/null
+++ b/vendor/orion/src/high_level/pwhash.rs
@@ -0,0 +1,990 @@
+// MIT License
+
+// Copyright (c) 2020-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.
+
+//! Password hashing and verification.
+//!
+//! # Use case:
+//! `orion::pwhash` is suitable for securely storing passwords.
+//!
+//! An example of this would be needing to store user passwords (from a sign-up
+//! at a webstore) in a server database,
+//! where a potential disclosure of the data in this database should not result
+//! in the user's actual passwords being disclosed as well.
+//!
+//! # About:
+//! - Uses Argon2i.
+//! - A salt of 16 bytes is automatically generated.
+//! - The password hash length is set to 32.
+//!
+//! [`PasswordHash`] provides two ways of retrieving the hashed password:
+//! - [`PasswordHash::unprotected_as_encoded()`] returns the hashed password in an encoded form.
+//! The encoding specifies the settings used to hash the password.
+//! - [`PasswordHash::unprotected_as_bytes()`] returns only the hashed password in raw bytes.
+//!
+//! The following is an example of how the encoded password hash might look:
+//! ```text
+//! $argon2i$v=19$m=8192,t=3,p=1$c21hbGxzYWx0$lmO1aPPy3x0CcvrKpFLi1TL/uSVJ/eO5hPHiWZFaWvY
+//! ```
+//!
+//! See a more detailed description of the [encoding format here].
+//!
+//! # Note:
+//! This implementation only supports a single thread/lane.
+//!
+//! # Parameters:
+//! - `password`: The password to be hashed.
+//! - `expected`: The expected password hash.
+//! - `iterations`: Iterations cost parameter for Argon2i.
+//! - `memory`: Memory (in kibibytes (KiB)) cost parameter for Argon2i.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - `memory` is less than 8.
+//! - `iterations` is less than 3.
+//! - The length of the `password` is greater than [`isize::MAX`].
+//! - The password hash does not match `expected`.
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - Failure to generate random bytes securely.
+//!
+//! # Security:
+//! - [`PasswordHash::unprotected_as_encoded()`] and [`PasswordHash::unprotected_as_bytes()`] should never
+//! be used to compare password hashes, as these will not run in constant-time.
+//! Either use [`hash_password_verify()`] or compare two [`PasswordHash`]es.
+//! - Choosing the correct cost parameters is important for security. Please refer to [libsodium's docs]
+//! for a description of how to do this.
+//!
+//! If the concrete cost parameters needed are unclear, please refer to [OWASP] for recommended minimum values.
+//!
+//! # Example:
+//! ```rust
+//! use orion::pwhash;
+//!
+//! let password = pwhash::Password::from_slice(b"Secret password")?;
+//!
+//! let hash = pwhash::hash_password(&password, 3, 1<<16)?;
+//! assert!(pwhash::hash_password_verify(&hash, &password).is_ok());
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [encoding format here]: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
+//! [libsodium's docs]: https://download.libsodium.org/doc/password_hashing/default_phf#guidelines-for-choosing-the-parameters
+//! [OWASP]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+pub use super::hltypes::Password;
+use super::hltypes::Salt;
+use crate::{
+ errors::UnknownCryptoError,
+ hazardous::kdf::argon2i::{self, LANES, MIN_MEMORY},
+};
+use ct_codecs::{Base64NoPadding, Decoder, Encoder};
+use zeroize::Zeroizing;
+
+#[cfg(feature = "serde")]
+use serde::{
+ de::{self, Deserialize, Deserializer},
+ ser::{Serialize, Serializer},
+};
+
+/// The length of the salt used for password hashing.
+pub const SALT_LENGTH: usize = 16;
+
+/// The length of the hashed password.
+pub const PWHASH_LENGTH: usize = 32;
+
+/// Minimum amount of iterations.
+pub(crate) const MIN_ITERATIONS: u32 = 3;
+
+/// A type to represent the `PasswordHash` that Argon2i returns when used for password hashing.
+///
+///
+/// # Errors:
+/// An error will be returned if:
+/// - The encoded password hash contains whitespace.
+/// - The encoded password hash has a parallelism count other than 1.
+/// - The encoded password contains any other fields than: The algorithm name,
+/// version, m, t, p and the salt and password hash.
+/// - The encoded password hash contains invalid Base64 encoding.
+/// - Any decimal parameter value, such as m, contains leading zeroes and is longer
+/// than a single character.
+/// - `iterations` is less than 3.
+/// - `memory` is less than 8.
+/// - `password` is not 32 bytes.
+/// - `salt` is not 16 bytes.
+/// - The encoded password hash contains numerical values that cannot
+/// be represented as a `u32`.
+/// - The encoded password hash length is less than [`PasswordHash::MIN_ENCODED_LEN`] or greater than [`PasswordHash::MAX_ENCODED_LEN`].
+/// - The parameters in the encoded password hash are not correctly ordered. The ordering must be:
+/// `$argon2i$v=19$m=<value>,t=<value>,p=<value>$<salt>$<hash>`
+/// # Panics:
+/// A panic will occur if:
+/// - Overflowing calculations happen on `usize` when decoding the password and salt from Base64.
+///
+/// # Security:
+/// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+/// that the type implements.
+/// - Never use `unprotected_as_bytes()` or `unprotected_as_encoded()` to compare password hashes,
+/// as that will not run in constant-time. Compare `PasswordHash`es directly using `==` instead.
+/// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+/// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+/// is implemented in such a way that the comparison happens in constant time. Thus, users should
+/// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+/// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+/// ```rust
+/// use orion::hazardous::mac::hmac::sha512::Tag;
+/// # use orion::errors::UnknownCryptoError;
+///
+/// # fn main() -> Result<(), Box<UnknownCryptoError>> {
+/// // Initialize an arbitrary, 64-byte tag.
+/// let tag = Tag::from_slice(&[1; 64])?;
+///
+/// // Secure, constant-time comparison with a byte slice
+/// assert_eq!(tag, &[1; 64][..]);
+///
+/// // Secure, constant-time comparison with another Tag
+/// assert_eq!(tag, Tag::from_slice(&[1; 64])?);
+/// # Ok(())
+/// # }
+/// ```
+pub struct PasswordHash {
+ encoded_password_hash: String,
+ password_hash: Vec<u8>,
+ salt: Salt,
+ iterations: u32,
+ memory: u32,
+}
+
+#[allow(clippy::len_without_is_empty)]
+impl PasswordHash {
+ /// Given a 16-byte salt (22 characters encoded) and 32-byte password hash (43 characters encoded),
+ /// and parameters (m, t) in decimal representation of 1..10 in length, 92 is the minimum length for an encoded password hash.
+ pub const MIN_ENCODED_LEN: usize = 92;
+
+ /// Given a 16-byte salt (22 characters encoded) and 32-byte password hash (43 characters encoded),
+ /// and parameters (m, t) in decimal representation of 1..10 in length, 110 is the maximum length for an encoded password hash.
+ pub const MAX_ENCODED_LEN: usize = 110;
+
+ /// Parse a decimal parameter value to a u32. Returns an error on overflow
+ /// and if the value has leading zeroes.
+ fn parse_decimal_value(value: &str) -> Result<u32, UnknownCryptoError> {
+ // See: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#decimal-encoding
+ if value.len() > 1 && value.starts_with('0') {
+ return Err(UnknownCryptoError);
+ }
+ // .parse::<T>() detects overflows (in debug and release builds)
+ // and rejects empty strings. If the value contains spaces, parsing
+ // also fails.
+ Ok(value.parse::<u32>()?)
+ }
+
+ /// Encode password hash, salt and parameters for storage.
+ fn encode(
+ password_hash: &[u8],
+ salt: &[u8],
+ iterations: u32,
+ memory: u32,
+ ) -> Result<String, UnknownCryptoError> {
+ Ok(format!(
+ "$argon2i$v=19$m={},t={},p=1${}${}",
+ memory,
+ iterations,
+ Base64NoPadding::encode_to_string(salt)?,
+ Base64NoPadding::encode_to_string(password_hash)?,
+ ))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from given byte slice and parameters.
+ pub fn from_slice(
+ password_hash: &[u8],
+ salt: &[u8],
+ iterations: u32,
+ memory: u32,
+ ) -> Result<Self, UnknownCryptoError> {
+ if password_hash.len() != PWHASH_LENGTH {
+ return Err(UnknownCryptoError);
+ }
+ if salt.len() != SALT_LENGTH {
+ return Err(UnknownCryptoError);
+ }
+ if iterations < MIN_ITERATIONS {
+ return Err(UnknownCryptoError);
+ }
+ if memory < MIN_MEMORY {
+ return Err(UnknownCryptoError);
+ }
+
+ let encoded_password_hash = Self::encode(password_hash, salt, iterations, memory)?;
+
+ Ok(Self {
+ encoded_password_hash,
+ password_hash: password_hash.into(),
+ salt: Salt::from_slice(salt)?,
+ iterations,
+ memory,
+ })
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from encoded password hash.
+ pub fn from_encoded(password_hash: &str) -> Result<Self, UnknownCryptoError> {
+ if password_hash.len() > Self::MAX_ENCODED_LEN
+ || password_hash.len() < Self::MIN_ENCODED_LEN
+ {
+ return Err(UnknownCryptoError);
+ }
+
+ if password_hash.contains(' ') {
+ return Err(UnknownCryptoError);
+ }
+
+ let parts_split = password_hash.split('$').collect::<Vec<&str>>();
+ if parts_split.len() != 6 {
+ return Err(UnknownCryptoError);
+ }
+ let mut parts = parts_split.into_iter();
+ if parts.next() != Some("") {
+ return Err(UnknownCryptoError);
+ }
+ if parts.next() != Some("argon2i") {
+ return Err(UnknownCryptoError);
+ }
+ if parts.next() != Some("v=19") {
+ return Err(UnknownCryptoError);
+ }
+
+ // Splits as ["m", "X", "t", "Y", "p", "Z"] where m=X, t=Y and p=Z.
+ let param_parts_split = parts
+ .next()
+ .unwrap()
+ .split(|v| v == '=' || v == ',')
+ .collect::<Vec<&str>>();
+ if param_parts_split.len() != 6 {
+ return Err(UnknownCryptoError);
+ }
+ let mut param_parts = param_parts_split.into_iter();
+
+ if param_parts.next() != Some("m") {
+ return Err(UnknownCryptoError);
+ }
+
+ let memory = Self::parse_decimal_value(param_parts.next().unwrap())?;
+ if memory < MIN_MEMORY {
+ return Err(UnknownCryptoError);
+ }
+
+ if param_parts.next() != Some("t") {
+ return Err(UnknownCryptoError);
+ }
+ let iterations = Self::parse_decimal_value(param_parts.next().unwrap())?;
+ if iterations < MIN_ITERATIONS {
+ return Err(UnknownCryptoError);
+ }
+
+ if param_parts.next() != Some("p") {
+ return Err(UnknownCryptoError);
+ }
+ let lanes = Self::parse_decimal_value(param_parts.next().unwrap())?;
+ if lanes != LANES {
+ return Err(UnknownCryptoError);
+ }
+
+ let salt = Base64NoPadding::decode_to_vec(parts.next().unwrap(), None)?;
+ if salt.len() != SALT_LENGTH {
+ return Err(UnknownCryptoError);
+ }
+ let password_hash_raw = Base64NoPadding::decode_to_vec(parts.next().unwrap(), None)?;
+ if password_hash_raw.len() != PWHASH_LENGTH {
+ return Err(UnknownCryptoError);
+ }
+
+ Ok(Self {
+ encoded_password_hash: password_hash.into(),
+ password_hash: password_hash_raw,
+ salt: Salt::from_slice(&salt)?,
+ iterations,
+ memory,
+ })
+ }
+
+ #[inline]
+ /// Return encoded password hash. __**Warning**__: Should not be used to verify
+ /// password hashes. This __**breaks protections**__ that the type implements.
+ pub fn unprotected_as_encoded(&self) -> &str {
+ self.encoded_password_hash.as_ref()
+ }
+
+ #[inline]
+ /// Return the password hash as byte slice. __**Warning**__: Should not be used unless strictly
+ /// needed. This __**breaks protections**__ that the type implements.
+ pub fn unprotected_as_bytes(&self) -> &[u8] {
+ self.password_hash.as_ref()
+ }
+
+ #[inline]
+ /// Return the length of the password hash.
+ pub fn len(&self) -> usize {
+ self.password_hash.len()
+ }
+
+ #[inline]
+ /// Return `true` if the password hash is empty, `false` otherwise.
+ ///
+ /// __NOTE__: This method should always return `false`, since there shouldn't be a way
+ /// to create an empty password hash.
+ pub fn is_empty(&self) -> bool {
+ debug_assert_eq!(self.encoded_password_hash.is_empty(), self.password_hash.is_empty(),
+ "Both the encoded password hash and the raw hash must be non-empty or empty at the same time.");
+ self.password_hash.is_empty()
+ }
+}
+
+impl core::fmt::Debug for PasswordHash {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "PasswordHash {{ encoded_password_hash: [***OMITTED***], password_hash: [***OMITTED***], iterations: \
+ {:?}, memory: {:?} }}",
+ self.iterations, self.memory
+ )
+ }
+}
+
+impl_ct_partialeq_trait!(PasswordHash, unprotected_as_bytes);
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+/// `PasswordHash` serializes as would a [`String`](std::string::String). Note that
+/// the serialized type likely does not have the same protections that Orion
+/// provides, such as constant-time operations. A good rule of thumb is to only
+/// serialize these types for storage. Don't operate on the serialized types.
+impl Serialize for PasswordHash {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let encoded_string = self.unprotected_as_encoded();
+ serializer.serialize_str(encoded_string)
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+/// `PasswordHash` deserializes from a [`String`](std::string::String).
+impl<'de> Deserialize<'de> for PasswordHash {
+ fn deserialize<D>(deserializer: D) -> Result<PasswordHash, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let encoded_str = String::deserialize(deserializer)?;
+ PasswordHash::from_encoded(&encoded_str).map_err(de::Error::custom)
+ }
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Hash a password using Argon2i.
+pub fn hash_password(
+ password: &Password,
+ iterations: u32,
+ memory: u32,
+) -> Result<PasswordHash, UnknownCryptoError> {
+ if iterations < MIN_ITERATIONS {
+ return Err(UnknownCryptoError);
+ }
+
+ // Cannot panic as this is a valid size.
+ let salt = Salt::generate(SALT_LENGTH).unwrap();
+ let mut buffer = Zeroizing::new([0u8; PWHASH_LENGTH]);
+
+ argon2i::derive_key(
+ password.unprotected_as_bytes(),
+ salt.as_ref(),
+ iterations,
+ memory,
+ None,
+ None,
+ buffer.as_mut(),
+ )?;
+
+ PasswordHash::from_slice(buffer.as_ref(), salt.as_ref(), iterations, memory)
+}
+
+/// Hash and verify a password using Argon2i. The Argon2i parameters `iterations`
+/// and `memory` will be pulled from the `expected: &PasswordHash` argument. If
+/// you want to manually specify the iterations and memory for Argon2i to use in
+/// hashing the `password` argument, see the
+/// [`hazardous::kdf`](crate::hazardous::kdf::argon2i) module.
+///
+/// # Example:
+/// ```rust
+/// use orion::pwhash;
+///
+/// let password = pwhash::Password::from_slice(b"Secret password")?;
+/// let wrong_password = pwhash::Password::from_slice(b"hunter2")?;
+///
+/// // Pretend these are stored somewhere and out-of-mind, e.g. in a database.
+/// let hash1 = pwhash::hash_password(&password, 3, 1<<15)?;
+/// let hash2 = pwhash::hash_password(&password, 4, 2<<15)?;
+///
+/// // We don't have to remember which password used what parameters when it's
+/// // time to verify them. Both will correctly return `Ok(())`.
+/// assert!(pwhash::hash_password_verify(&hash1, &password).is_ok());
+/// assert!(pwhash::hash_password_verify(&hash2, &password).is_ok());
+///
+/// // The only way to get a failing result is to use the wrong password.
+/// assert!(pwhash::hash_password_verify(&hash1, &wrong_password).is_err());
+/// # Ok::<(), orion::errors::UnknownCryptoError>(())
+/// ```
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+pub fn hash_password_verify(
+ expected: &PasswordHash,
+ password: &Password,
+) -> Result<(), UnknownCryptoError> {
+ let mut buffer = Zeroizing::new([0u8; PWHASH_LENGTH]);
+
+ argon2i::verify(
+ expected.unprotected_as_bytes(),
+ password.unprotected_as_bytes(),
+ expected.salt.as_ref(),
+ expected.iterations,
+ expected.memory,
+ None,
+ None,
+ buffer.as_mut(),
+ )
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let valid = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let password_hash = PasswordHash::from_encoded(valid).unwrap();
+ let debug = format!("{:?}", password_hash);
+ let expected = "PasswordHash { encoded_password_hash: [***OMITTED***], password_hash: [***OMITTED***], iterations: 3, memory: 65536 }";
+ assert_eq!(debug, expected);
+ }
+
+ #[cfg(feature = "serde")]
+ mod test_serde_impls {
+ use super::*;
+
+ #[test]
+ fn test_valid_deserialization() {
+ let encoded_hash = "$argon2i$v=19$m=65536,t=3,p=1$c29tZXNhbHRzb21lc2FsdA$fRsRY9PAt5H+qAKuXRzL0/6JbFShsCd62W5aHzESk/c";
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ let deserialized: PasswordHash =
+ serde_json::from_str(format!("\"{}\"", encoded_hash).as_str()).unwrap();
+ assert_eq!(deserialized, expected);
+ }
+
+ #[test]
+ fn test_valid_serialization() {
+ let encoded_hash = "$argon2i$v=19$m=65536,t=3,p=1$c29tZXNhbHRzb21lc2FsdA$fRsRY9PAt5H+qAKuXRzL0/6JbFShsCd62W5aHzESk/c";
+ let hash = PasswordHash::from_encoded(encoded_hash).unwrap();
+ let serialized: String = serde_json::to_string(&hash).unwrap();
+ assert_eq!(serialized, format!("\"{}\"", encoded_hash));
+ }
+ }
+
+ /// The tests herein were generated with the CLI tool from the reference implementation at:
+ /// https://github.com/P-H-C/phc-winner-argon2/commit/62358ba2123abd17fccf2a108a301d4b52c01a7c
+ mod test_encoding_from_ref {
+ use super::*;
+ use hex;
+
+ #[test]
+ fn test_encoding_and_verify_1() {
+ let password = Password::from_slice(b"password").unwrap();
+ let raw_hash =
+ hex::decode("7d1b1163d3c0b791fea802ae5d1ccbd3fe896c54a1b0277ad96e5a1f311293f7")
+ .unwrap();
+ let encoded_hash = "$argon2i$v=19$m=65536,t=3,p=1$c29tZXNhbHRzb21lc2FsdA$fRsRY9PAt5H+qAKuXRzL0/6JbFShsCd62W5aHzESk/c";
+
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ assert_eq!(expected.unprotected_as_bytes(), &raw_hash[..]);
+ assert!(hash_password_verify(&expected, &password).is_ok());
+ }
+
+ #[test]
+ fn test_encoding_and_verify_2() {
+ let password = Password::from_slice(b"passwordPASSWORDPassword").unwrap();
+ let raw_hash =
+ hex::decode("ed4b0fd657e165f9ffe90f66ff315fbec878e629f03b2d6468d4b17a50c796aa")
+ .unwrap();
+ let encoded_hash = "$argon2i$v=19$m=65536,t=3,p=1$c29tZXNhbHRzb21lc2FsdA$7UsP1lfhZfn/6Q9m/zFfvsh45inwOy1kaNSxelDHlqo";
+
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ assert_eq!(expected.unprotected_as_bytes(), &raw_hash[..]);
+ assert!(hash_password_verify(&expected, &password).is_ok());
+ }
+
+ #[test]
+ fn test_encoding_and_verify_3() {
+ // Different salt from test 2
+ let password = Password::from_slice(b"passwordPASSWORDPassword").unwrap();
+ let raw_hash =
+ hex::decode("fa9ea96fecd0998251d698c1303edda4df3889a39bfa87cd5e7b8656ef61b510")
+ .unwrap();
+ let encoded_hash = "$argon2i$v=19$m=65536,t=3,p=1$U29tZVNhbHRTb21lU2FsdA$+p6pb+zQmYJR1pjBMD7dpN84iaOb+ofNXnuGVu9htRA";
+
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ assert_eq!(expected.unprotected_as_bytes(), &raw_hash[..]);
+ assert!(hash_password_verify(&expected, &password).is_ok());
+ }
+
+ #[test]
+ fn test_encoding_and_verify_4() {
+ let password = Password::from_slice(b"passwordPASSWORDPassword").unwrap();
+ let raw_hash =
+ hex::decode("fb3e0cdf7b10970bf6711c151861851566006f8986c9109ba2cdd5d98f9ca9d7")
+ .unwrap();
+ let encoded_hash = "$argon2i$v=19$m=256,t=3,p=1$c29tZXNhbHRzb21lc2FsdA$+z4M33sQlwv2cRwVGGGFFWYAb4mGyRCbos3V2Y+cqdc";
+
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ assert_eq!(expected.unprotected_as_bytes(), &raw_hash[..]);
+ assert!(hash_password_verify(&expected, &password).is_ok());
+ }
+
+ #[test]
+ fn test_encoding_and_verify_5() {
+ let password = Password::from_slice(b"passwordPASSWORDPassword").unwrap();
+ let raw_hash =
+ hex::decode("9b134c4c1c34e66170d1088c18be3a8e0f4a1837d4c069703ce62f85248b1e8f")
+ .unwrap();
+ let encoded_hash = "$argon2i$v=19$m=256,t=4,p=1$c29tZXNhbHRzb21lc2FsdA$mxNMTBw05mFw0QiMGL46jg9KGDfUwGlwPOYvhSSLHo8";
+
+ let expected = PasswordHash::from_encoded(encoded_hash).unwrap();
+ assert_eq!(expected.unprotected_as_bytes(), &raw_hash[..]);
+ assert!(hash_password_verify(&expected, &password).is_ok());
+ }
+ }
+
+ mod test_password_hash {
+ use super::*;
+
+ #[test]
+ fn test_password_hash_eq() {
+ let password_hash =
+ PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 1 << 16).unwrap();
+ assert_eq!(password_hash.len(), 32);
+ assert_eq!(password_hash.unprotected_as_bytes(), &[0u8; 32]);
+
+ let password_hash_again =
+ PasswordHash::from_encoded(password_hash.unprotected_as_encoded()).unwrap();
+ assert_eq!(password_hash, password_hash_again);
+ }
+
+ #[test]
+ fn test_password_hash_ne() {
+ let password_hash =
+ PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 1 << 16).unwrap();
+ assert_eq!(password_hash.len(), 32);
+ assert_eq!(password_hash.unprotected_as_bytes(), &[0u8; 32]);
+
+ let password_hash_again =
+ PasswordHash::from_slice(&[1u8; 32], &[0u8; 16], 3, 1 << 16).unwrap();
+
+ assert_ne!(password_hash, password_hash_again);
+ }
+
+ #[test]
+ fn test_valid_encoded_password() {
+ let valid = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ assert!(PasswordHash::from_encoded(valid).is_ok());
+ }
+
+ #[test]
+ fn test_bad_encoding_missing_dollar() {
+ let first_missing = "argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let second_missing = "$argon2iv=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let third_missing = "$argon2i$v=19m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let fourth_missing = "$argon2i$v=19$m=65536,t=3,p=1cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let fifth_missing = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(first_missing).is_err());
+ assert!(PasswordHash::from_encoded(second_missing).is_err());
+ assert!(PasswordHash::from_encoded(third_missing).is_err());
+ assert!(PasswordHash::from_encoded(fourth_missing).is_err());
+ assert!(PasswordHash::from_encoded(fifth_missing).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_missing_comma() {
+ let first_missing = "$argon2i$v=19$m=65536t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let second_missing = "$argon2i$v=19$m=65536,t=3p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(first_missing).is_err());
+ assert!(PasswordHash::from_encoded(second_missing).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_missing_equals() {
+ let first_missing = "$argon2i$v19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let second_missing = "$argon2$iv=19$m65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let third_missing = "$argon2i$v=19$m=65536,t3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let fourth_missing = "$argon2i$v=19$m=65536,t=3,p1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(first_missing).is_err());
+ assert!(PasswordHash::from_encoded(second_missing).is_err());
+ assert!(PasswordHash::from_encoded(third_missing).is_err());
+ assert!(PasswordHash::from_encoded(fourth_missing).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_whitespace() {
+ let first = "$argon2i$v=19$m=65536,t=3, p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let second = " $argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let third = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA ";
+
+ assert!(PasswordHash::from_encoded(first).is_err());
+ assert!(PasswordHash::from_encoded(second).is_err());
+ assert!(PasswordHash::from_encoded(third).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_threads() {
+ let one = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let zero = "$argon2i$v=19$m=65536,t=3,p=0$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let two = "$argon2i$v=19$m=65536,t=3,p=2$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(one).is_ok());
+ assert!(PasswordHash::from_encoded(zero).is_err());
+ assert!(PasswordHash::from_encoded(two).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_memory() {
+ let exact_min = "$argon2i$v=19$m=8,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let less = "$argon2i$v=19$m=7,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ // Throws error during parsing as u32
+ let u32_overflow = format!("$argon2i$v=19$m={},t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA", u64::MAX);
+
+ assert!(PasswordHash::from_encoded(exact_min).is_ok());
+ assert!(PasswordHash::from_encoded(less).is_err());
+ assert!(PasswordHash::from_encoded(&u32_overflow).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_iterations() {
+ let exact_min = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let less = "$argon2i$v=19$m=65536,t=2,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ // Throws error during parsing as u32
+ let u32_overflow = format!("$argon2i$v=19$m=65536,t={},p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA", u64::MAX);
+
+ assert!(PasswordHash::from_encoded(exact_min).is_ok());
+ assert!(PasswordHash::from_encoded(less).is_err());
+ assert!(PasswordHash::from_encoded(&u32_overflow).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_algo() {
+ let argon2id = "$argon2id$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let argon2d = "$argon2d$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let nothing = "$$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(argon2d).is_err());
+ assert!(PasswordHash::from_encoded(argon2id).is_err());
+ assert!(PasswordHash::from_encoded(nothing).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_version() {
+ let v13 = "$argon2i$v=13$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let v0 = "$argon2i$v=0$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let nothing = "$argon2i$v=$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(v13).is_err());
+ assert!(PasswordHash::from_encoded(v0).is_err());
+ assert!(PasswordHash::from_encoded(nothing).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_order() {
+ let version_first = "$v=19$argon2i$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let t_before_m = "$argon2i$v=19$t=3,m=65536,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let p_before_t = "$argon2i$v=19$m=65536,p=1,t=3$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let p_before_m = "$argon2i$v=19$p=1,m=65536,t=3$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let pass_before_salt = "$argon2i$v=19$m=65536,t=3,p=1$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA$cHBwcHBwcHBwcHBwcHBwcA";
+ let salt_first = "$cHBwcHBwcHBwcHBwcHBwcA$argon2i$v=19$m=65536,t=3,p=1$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let pass_first = "$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA";
+
+ assert!(PasswordHash::from_encoded(version_first).is_err());
+ assert!(PasswordHash::from_encoded(t_before_m).is_err());
+ assert!(PasswordHash::from_encoded(p_before_t).is_err());
+ assert!(PasswordHash::from_encoded(p_before_m).is_err());
+ assert!(PasswordHash::from_encoded(pass_before_salt).is_err());
+ assert!(PasswordHash::from_encoded(salt_first).is_err());
+ assert!(PasswordHash::from_encoded(pass_first).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_salt() {
+ let exact = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let nothing =
+ "$argon2i$v=19$m=65536,t=3,p=1$$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let above = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcAA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(exact).is_ok());
+ assert!(PasswordHash::from_encoded(nothing).is_err());
+ assert!(PasswordHash::from_encoded(above).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_invalid_password() {
+ let exact = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let nothing = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$";
+ let above = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAA";
+
+ assert!(PasswordHash::from_encoded(exact).is_ok());
+ assert!(PasswordHash::from_encoded(nothing).is_err());
+ assert!(PasswordHash::from_encoded(above).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_bad_parsing_integers() {
+ let j_instead_of_mem = "$argon2i$v=19$m=j,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(j_instead_of_mem).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_first_not_empty() {
+ // Nothing should precede "$argon2i"
+ let non_empty_first = "apples$argon2i$v=19$m=4096,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(non_empty_first).is_err());
+ }
+
+ #[test]
+ fn test_bad_encoding_bad_p() {
+ let p_is_j = "$argon2i$v=19$m=4096,t=3,j=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let p_gone = "$argon2i$v=19$m=4096,t=3,=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(p_is_j).is_err());
+ assert!(PasswordHash::from_encoded(p_gone).is_err());
+ }
+
+ #[test]
+ fn test_decimal_value_reject_leading_zeroes() {
+ // https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#decimal-encoding
+ // According to the specification, the decimal parameters may not start with 0, if there is more than
+ // one character in the string. .parse::<u32>() will ignore leading 0's, so it will parse "0032" -> 32u32.
+ // Test here that these cases are detected and rejected by returning an error.
+ let valid = "$argon2i$v=19$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let invalid0 = "$argon2i$v=019$m=65536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let invalid1 = "$argon2i$v=19$m=065536,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let invalid2 = "$argon2i$v=19$m=65536,t=03,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ let invalid3 = "$argon2i$v=19$m=65536,t=3,p=01$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+
+ assert!(PasswordHash::from_encoded(valid).is_ok());
+ assert!(PasswordHash::from_encoded(invalid0).is_err());
+ assert!(PasswordHash::from_encoded(invalid1).is_err());
+ assert!(PasswordHash::from_encoded(invalid2).is_err());
+ assert!(PasswordHash::from_encoded(invalid3).is_err());
+ }
+
+ #[test]
+ fn test_bounds_max_min_encoded_len() {
+ let minimum = "$argon2i$v=19$m=8,t=3,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ assert_eq!(minimum.len(), PasswordHash::MIN_ENCODED_LEN);
+ let maximum = "$argon2i$v=19$m=1111111111,t=1111111111,p=1$cHBwcHBwcHBwcHBwcHBwcA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ assert_eq!(maximum.len(), PasswordHash::MAX_ENCODED_LEN);
+
+ // salt removed one char
+ let less = "$argon2i$v=19$m=8,t=3,p=1$cHBwcHBwcHBwcHBwcHBwc$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ assert_eq!(less.len(), PasswordHash::MIN_ENCODED_LEN - 1);
+ // salt added one char
+ let more = "$argon2i$v=19$m=1111111111,t=1111111111,p=1$cHBwcHBwcHBwcHBwcHBwcAA$MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA";
+ assert_eq!(more.len(), PasswordHash::MAX_ENCODED_LEN + 1);
+
+ assert!(PasswordHash::from_encoded(minimum).is_ok());
+ assert!(PasswordHash::from_encoded(maximum).is_ok());
+ assert!(PasswordHash::from_encoded(less).is_err());
+ assert!(PasswordHash::from_encoded(more).is_err());
+ }
+
+ #[test]
+ fn test_from_slice_password() {
+ assert!(PasswordHash::from_slice(&[0u8; 31], &[0u8; 16], 3, 1 << 16).is_err());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 1 << 16).is_ok());
+ assert!(PasswordHash::from_slice(&[0u8; 33], &[0u8; 16], 3, 1 << 16).is_err());
+ }
+
+ #[test]
+ fn test_from_slice_salt() {
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 15], 3, 1 << 16).is_err());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 1 << 16).is_ok());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 17], 3, 1 << 16).is_err());
+ }
+
+ #[test]
+ fn test_from_slice_mem() {
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 7).is_err());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 8).is_ok());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 9).is_ok());
+ }
+
+ #[test]
+ fn test_from_slice_bad_iter() {
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 2, 1 << 16).is_err());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 3, 1 << 16).is_ok());
+ assert!(PasswordHash::from_slice(&[0u8; 32], &[0u8; 16], 4, 1 << 16).is_ok());
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// If valid params then it's always valid to encode/decode.
+ fn prop_always_produce_valid_encoding(
+ password: Vec<u8>,
+ salt: Vec<u8>,
+ iterations: u32,
+ memory: u32,
+ ) -> bool {
+ let res = PasswordHash::from_slice(&password[..], &salt[..], iterations, memory);
+ if res.is_ok() {
+ assert!(PasswordHash::from_encoded(res.unwrap().unprotected_as_encoded()).is_ok());
+ }
+
+ true
+ }
+ }
+
+ mod test_pwhash_and_verify {
+ use super::*;
+
+ #[test]
+ fn test_argon2i_verify() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ let dk = hash_password(&password, 3, 4096).unwrap();
+
+ assert!(hash_password_verify(&dk, &password).is_ok());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_password() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let mut pwd_mod = dk.unprotected_as_bytes().to_vec();
+ pwd_mod[0..32].copy_from_slice(&[0u8; 32]);
+ let modified = PasswordHash::from_slice(&pwd_mod, dk.salt.as_ref(), 3, 4096).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_memory() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let encoded = dk.unprotected_as_encoded();
+
+ let mut modified = encoded.to_string();
+ let memory_offset = modified.find("$m=4096").unwrap();
+ modified.replace_range(memory_offset..memory_offset + 7, "$m=2048");
+
+ let modified = PasswordHash::from_encoded(&modified).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_iterations() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let encoded = dk.unprotected_as_encoded();
+
+ let mut modified = encoded.to_string();
+ let iterations_offset = modified.find(",t=3").unwrap();
+ modified.replace_range(iterations_offset..iterations_offset + 4, ",t=4");
+
+ let modified = PasswordHash::from_encoded(&modified).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_memory_and_iterations() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let encoded = dk.unprotected_as_encoded();
+
+ let mut modified = encoded.to_string();
+ let memory_offset = modified.find("$m=4096").unwrap();
+ let iterations_offset = modified.find(",t=3").unwrap();
+ modified.replace_range(memory_offset..memory_offset + 7, "$m=2048");
+ modified.replace_range(iterations_offset..iterations_offset + 4, ",t=4");
+
+ let modified = PasswordHash::from_encoded(&modified).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_salt() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let mut salt_mod = dk.salt.as_ref().to_vec();
+ salt_mod[0..16].copy_from_slice(&[0u8; 16]);
+ let modified =
+ PasswordHash::from_slice(dk.unprotected_as_bytes(), &salt_mod, 3, 4096).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_verify_err_modified_salt_and_password() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+
+ let dk = hash_password(&password, 3, 4096).unwrap();
+ let mut pwd_mod = dk.unprotected_as_bytes().to_vec();
+ let mut salt_mod = dk.salt.as_ref().to_vec();
+ pwd_mod[0..32].copy_from_slice(&[0u8; 32]);
+ salt_mod[0..16].copy_from_slice(&[0u8; 16]);
+ let modified = PasswordHash::from_slice(&pwd_mod, &salt_mod, 3, 4096).unwrap();
+
+ assert!(hash_password_verify(&modified, &password).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_invalid_iterations() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ assert!(hash_password(&password, MIN_ITERATIONS - 1, 4096).is_err());
+ }
+
+ #[test]
+ fn test_argon2i_invalid_memory() {
+ let password = Password::from_slice(&[0u8; 64]).unwrap();
+ assert!(hash_password(&password, MIN_ITERATIONS, MIN_MEMORY - 1).is_err());
+ }
+ }
+}
diff --git a/vendor/orion/src/lib.rs b/vendor/orion/src/lib.rs
new file mode 100644
index 0000000..5064526
--- /dev/null
+++ b/vendor/orion/src/lib.rs
@@ -0,0 +1,117 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+//! A usable pure-Rust cryptography library.
+//!
+//! ## Authenticated secret-key encryption
+//! [`orion::aead`] offers authenticated secret-key encryption using
+//! XChaCha20Poly1305.
+//!
+//! ## Password hashing and verification
+//! [`orion::pwhash`] offers password hashing and verification using Argon2i.
+//!
+//! ## Key derivation
+//! [`orion::kdf`] offers key derivation using Argon2i.
+//!
+//! ## Message authentication
+//! [`orion::auth`] offers message authentication and verification using BLAKE2b.
+//!
+//! ## Hashing
+//! [`orion::hash`] offers hashing using BLAKE2b.
+//!
+//! ## Key exchange
+//! [`orion::kex`] offers ephemeral key exchange using X25519 and BLAKE2b.
+//!
+//! ### A note on `no_std`:
+//! When Orion is used in a `no_std` context, the high-level API is not available, since it relies on access to the systems random number generator.
+//!
+//! More information about Orion is available in the [wiki].
+//!
+//! [`orion::aead`]: crate::aead
+//! [`orion::pwhash`]: crate::pwhash
+//! [`orion::kdf`]: crate::kdf
+//! [`orion::auth`]: crate::auth
+//! [`orion::hash`]: crate::hash
+//! [`orion::kex`]: crate::kex
+//! [wiki]: https://github.com/orion-rs/orion/wiki
+
+#![cfg_attr(not(feature = "safe_api"), no_std)]
+#![forbid(unsafe_code)]
+#![deny(clippy::mem_forget)]
+#![warn(
+ missing_docs,
+ rust_2018_idioms,
+ trivial_casts,
+ unused_qualifications,
+ overflowing_literals
+)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+extern crate quickcheck;
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+#[macro_use(quickcheck)]
+extern crate quickcheck_macros;
+
+#[cfg(feature = "alloc")]
+#[cfg_attr(feature = "alloc", macro_use)]
+extern crate alloc;
+
+#[macro_use]
+mod typedefs;
+
+#[macro_use]
+/// Utilities such as constant-time comparison.
+pub mod util;
+
+/// Errors for Orion's cryptographic operations.
+pub mod errors;
+
+/// \[__**Caution**__\] Low-level API.
+pub mod hazardous;
+
+#[cfg(feature = "safe_api")]
+mod high_level;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::hash;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::aead;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::auth;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::pwhash;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::kdf;
+
+#[cfg(feature = "safe_api")]
+pub use high_level::kex;
+
+#[doc(hidden)]
+/// Testing framework.
+pub mod test_framework;
diff --git a/vendor/orion/src/test_framework/aead_interface.rs b/vendor/orion/src/test_framework/aead_interface.rs
new file mode 100644
index 0000000..b19c44f
--- /dev/null
+++ b/vendor/orion/src/test_framework/aead_interface.rs
@@ -0,0 +1,379 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+#![allow(non_snake_case)]
+#[cfg(feature = "safe_api")]
+use crate::errors::UnknownCryptoError;
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+use crate::test_framework::streamcipher_interface::TestingRandom;
+
+#[allow(clippy::too_many_arguments)]
+#[cfg(feature = "safe_api")]
+/// Test runner for AEADs.
+pub fn AeadTestRunner<Sealer, Opener, Key, Nonce>(
+ sealer: Sealer,
+ opener: Opener,
+ key: Key,
+ nonce: Nonce,
+ input: &[u8],
+ expected_ct_with_tag: Option<&[u8]>,
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ seal_dst_out_length(&sealer, &key, &nonce, input, tag_size, aad);
+ open_dst_out_length(&sealer, &opener, &key, &nonce, input, tag_size, aad);
+ open_modified_tag_err(&sealer, &opener, &key, &nonce, input, tag_size, aad);
+ open_modified_ciphertext_err(&sealer, &opener, &key, &nonce, input, tag_size, aad);
+ open_modified_aad_err(&sealer, &opener, &key, &nonce, input, tag_size, aad);
+ none_or_empty_some_aad_same_result(&sealer, &opener, &key, &nonce, input, tag_size);
+ seal_open_equals_expected(
+ &sealer,
+ &opener,
+ &key,
+ &nonce,
+ input,
+ expected_ct_with_tag,
+ tag_size,
+ aad,
+ );
+ seal_plaintext_length(&sealer, &key, &nonce, tag_size, aad);
+ open_ciphertext_with_tag_length(&sealer, &opener, &key, &nonce, tag_size, aad);
+}
+
+#[cfg(feature = "safe_api")]
+/// Related bug: <https://github.com/orion-rs/orion/issues/52>
+/// Test dst_out mutable array sizes when using seal().
+fn seal_dst_out_length<Sealer, Key, Nonce>(
+ sealer: &Sealer,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ assert!(sealer(key, nonce, input, default_aad, &mut dst_out_ct).is_ok());
+
+ let mut dst_out_ct_more = vec![0u8; input.len() + (tag_size + 1)];
+ // Related bug: #52
+ assert!(sealer(key, nonce, input, default_aad, &mut dst_out_ct_more).is_ok());
+
+ let mut dst_out_ct_more_double = vec![0u8; input.len() + (tag_size * 2)];
+ // Related bug: #52
+ assert!(sealer(key, nonce, input, default_aad, &mut dst_out_ct_more_double).is_ok());
+
+ let mut dst_out_ct_less = vec![0u8; input.len() + (tag_size - 1)];
+ assert!(sealer(key, nonce, input, default_aad, &mut dst_out_ct_less).is_err());
+}
+
+#[cfg(feature = "safe_api")]
+/// Related bug: <https://github.com/orion-rs/orion/issues/52>
+/// Test input sizes when using seal().
+fn seal_plaintext_length<Sealer, Key, Nonce>(
+ sealer: &Sealer,
+ key: &Key,
+ nonce: &Nonce,
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let input_0 = vec![0u8; 0];
+ let mut dst_out_ct_0 = vec![0u8; input_0.len() + tag_size];
+ assert!(sealer(key, nonce, &input_0, default_aad, &mut dst_out_ct_0).is_ok());
+
+ let input_1 = vec![0u8; 1];
+ let mut dst_out_ct_1 = vec![0u8; input_1.len() + tag_size];
+ assert!(sealer(key, nonce, &input_1, default_aad, &mut dst_out_ct_1).is_ok());
+
+ let input_128 = vec![0u8; 128];
+ let mut dst_out_ct_128 = vec![0u8; input_128.len() + tag_size];
+ assert!(sealer(key, nonce, &input_128, default_aad, &mut dst_out_ct_128).is_ok());
+}
+
+#[cfg(feature = "safe_api")]
+/// Related bug: <https://github.com/orion-rs/orion/issues/52>
+/// Test dst_out mutable array sizes when using open().
+fn open_dst_out_length<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ sealer(key, nonce, input, default_aad, &mut dst_out_ct).unwrap();
+
+ let mut dst_out_pt = vec![0u8; input.len()];
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt).is_ok());
+
+ let mut dst_out_pt_0 = [0u8; 0];
+ let empty_out_res = opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt_0);
+ if input.is_empty() {
+ assert!(empty_out_res.is_ok());
+ } else {
+ assert!(empty_out_res.is_err());
+ }
+
+ if !input.is_empty() {
+ let mut dst_out_pt_less = vec![0u8; input.len() - 1];
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt_less).is_err());
+ }
+
+ let mut dst_out_pt_more = vec![0u8; input.len() + 1];
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt_more).is_ok());
+}
+
+#[cfg(feature = "safe_api")]
+/// Test input sizes when using open().
+fn open_ciphertext_with_tag_length<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+ let mut dst_out_pt = vec![0u8; tag_size];
+
+ assert!(opener(key, nonce, &[0u8; 0], default_aad, &mut dst_out_pt).is_err());
+
+ assert!(opener(
+ key,
+ nonce,
+ &vec![0u8; tag_size - 1],
+ default_aad,
+ &mut dst_out_pt
+ )
+ .is_err());
+
+ let mut dst_out_ct = vec![0u8; tag_size];
+ sealer(key, nonce, &[0u8; 0], default_aad, &mut dst_out_ct).unwrap();
+
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt).is_ok());
+}
+
+#[allow(clippy::too_many_arguments)]
+#[cfg(feature = "safe_api")]
+/// Test that sealing and opening produces the expected ciphertext.
+fn seal_open_equals_expected<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ expected_ct_with_tag: Option<&[u8]>,
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ sealer(key, nonce, input, default_aad, &mut dst_out_ct).unwrap();
+ if let Some(expected) = expected_ct_with_tag {
+ assert_eq!(expected, &dst_out_ct[..]);
+ }
+
+ let mut dst_out_pt = input.to_vec();
+ opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt).unwrap();
+ assert_eq!(input, &dst_out_pt[..]);
+ if let Some(expected) = expected_ct_with_tag {
+ opener(key, nonce, expected, default_aad, &mut dst_out_pt).unwrap();
+ assert_eq!(input, &dst_out_pt[..]);
+ }
+}
+
+#[cfg(feature = "safe_api")]
+/// When opening sealed data with a modified tag, an error should be returned.
+fn open_modified_tag_err<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ sealer(key, nonce, input, default_aad, &mut dst_out_ct).unwrap();
+ // Modify the first byte of the authentication tag.
+ dst_out_ct[input.len() + 1] ^= 1;
+
+ let mut dst_out_pt = input.to_vec();
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt).is_err());
+}
+
+#[cfg(feature = "safe_api")]
+/// When opening sealed data with a modified ciphertext, an error should be returned.
+fn open_modified_ciphertext_err<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let mut input = input;
+ if input.is_empty() {
+ input = &[0u8; 1];
+ }
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ sealer(key, nonce, input, default_aad, &mut dst_out_ct).unwrap();
+ // Modify the first byte of the ciphertext.
+ dst_out_ct[0] ^= 1;
+
+ let mut dst_out_pt = input.to_vec();
+ assert!(opener(key, nonce, &dst_out_ct, default_aad, &mut dst_out_pt).is_err());
+}
+
+#[cfg(feature = "safe_api")]
+/// When opening sealed data with modified aad, an error should be returned.
+fn open_modified_aad_err<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+ aad: &[u8],
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let default_aad = if aad.is_empty() { None } else { Some(aad) };
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ sealer(key, nonce, input, default_aad, &mut dst_out_ct).unwrap();
+
+ let mut dst_out_pt = input.to_vec();
+ assert!(opener(key, nonce, &dst_out_ct, Some(b"BAD AAD"), &mut dst_out_pt).is_err());
+}
+
+#[cfg(feature = "safe_api")]
+/// Using None or Some with empty slice should produce the exact same result.
+fn none_or_empty_some_aad_same_result<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+ tag_size: usize,
+) where
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let mut dst_out_ct_none = vec![0u8; input.len() + tag_size];
+ let mut dst_out_ct_some_empty = vec![0u8; input.len() + tag_size];
+
+ sealer(key, nonce, input, None, &mut dst_out_ct_none).unwrap();
+ sealer(
+ key,
+ nonce,
+ input,
+ Some(&[0u8; 0]),
+ &mut dst_out_ct_some_empty,
+ )
+ .unwrap();
+
+ assert_eq!(dst_out_ct_none, dst_out_ct_some_empty);
+
+ let mut dst_out_pt = vec![0u8; input.len()];
+ assert!(opener(
+ key,
+ nonce,
+ &dst_out_ct_none,
+ Some(&[0u8; 0]),
+ &mut dst_out_pt
+ )
+ .is_ok());
+ assert!(opener(key, nonce, &dst_out_ct_some_empty, None, &mut dst_out_pt).is_ok());
+}
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+/// Test that sealing and opening with different secret-key/nonce yields an error.
+pub fn test_diff_params_err<Sealer, Opener, Key, Nonce>(
+ sealer: &Sealer,
+ opener: &Opener,
+ input: &[u8],
+ tag_size: usize,
+) where
+ Key: TestingRandom + PartialEq<Key>,
+ Nonce: TestingRandom + PartialEq<Nonce>,
+ Sealer: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Opener: Fn(&Key, &Nonce, &[u8], Option<&[u8]>, &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let sk1 = Key::gen();
+ let sk2 = Key::gen();
+ assert!(sk1 != sk2);
+
+ let n1 = Nonce::gen();
+ let n2 = Nonce::gen();
+ assert!(n1 != n2);
+
+ let mut dst_out_ct = vec![0u8; input.len() + tag_size];
+ let mut dst_out_pt = vec![0u8; input.len()];
+
+ // Different secret key
+ sealer(&sk1, &n1, input, None, &mut dst_out_ct).unwrap();
+ assert!(opener(&sk2, &n1, &dst_out_ct, None, &mut dst_out_pt).is_err());
+
+ // Different nonce
+ sealer(&sk1, &n1, input, None, &mut dst_out_ct).unwrap();
+ assert!(opener(&sk1, &n2, &dst_out_ct, None, &mut dst_out_pt).is_err());
+}
diff --git a/vendor/orion/src/test_framework/incremental_interface.rs b/vendor/orion/src/test_framework/incremental_interface.rs
new file mode 100644
index 0000000..6bb14b9
--- /dev/null
+++ b/vendor/orion/src/test_framework/incremental_interface.rs
@@ -0,0 +1,343 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+use crate::errors::UnknownCryptoError;
+use core::marker::PhantomData;
+
+/// Trait to define default streaming contexts that can be tested.
+pub trait TestableStreamingContext<T: PartialEq> {
+ /// Streaming context function to reset the internal state.
+ fn reset(&mut self) -> Result<(), UnknownCryptoError>;
+
+ /// Streaming context function to update the internal state.
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Streaming context function to finalize the internal state.
+ fn finalize(&mut self) -> Result<T, UnknownCryptoError>;
+
+ /// Streaming context function to combine new(), update() and finalize() from the internal state.
+ fn one_shot(input: &[u8]) -> Result<T, UnknownCryptoError>;
+
+ /// Streaming context function to verify pre-computed results.
+ fn verify_result(expected: &T, input: &[u8]) -> Result<(), UnknownCryptoError>;
+
+ /// Testing utility-function that compares the internal state to another.
+ fn compare_states(state_1: &Self, state_2: &Self);
+}
+
+#[allow(dead_code)] // Allow because blocksize field is only used with std.
+/// A streaming context tester.
+pub struct StreamingContextConsistencyTester<R, T> {
+ _return_type: PhantomData<R>,
+ // The initial context to base further calls upon.
+ _initial_context: T,
+ blocksize: usize,
+}
+
+impl<R, T> StreamingContextConsistencyTester<R, T>
+where
+ R: PartialEq + core::fmt::Debug,
+ T: TestableStreamingContext<R> + Clone,
+{
+ /// The streaming interface tester is created utilizing an initialized
+ /// streaming state.
+ pub fn new(streaming_context: T, blocksize: usize) -> Self {
+ Self {
+ _return_type: PhantomData,
+ _initial_context: streaming_context,
+ blocksize,
+ }
+ }
+
+ // Default input to process.
+ // The number 37 has no particular meaning.
+ const DEFAULT_INPUT: [u8; 37] = [255u8; 37];
+
+ #[cfg(feature = "safe_api")]
+ /// Run all consistency tests given some input data.
+ /// Usually used with quickcheck.
+ pub fn run_all_tests_property(&self, data: &[u8]) {
+ self.consistency(data);
+ self.consistency(&[0u8; 0]);
+ self.produces_same_state(data);
+
+ // Following test requires std.
+ self.incremental_and_one_shot(data);
+
+ self.double_finalize_with_reset_no_update_ok(data);
+ self.double_finalize_with_reset_ok(data);
+ self.double_finalize_err(data);
+ self.update_after_finalize_with_reset_ok(data);
+ self.update_after_finalize_err(data);
+ self.double_reset_ok(data);
+ self.immediate_finalize();
+ Self::verify_same_input_ok(data);
+ Self::verify_diff_input_err(data);
+ }
+
+ #[cfg(feature = "safe_api")]
+ /// Used when quickcheck is not available to generate input.
+ /// Default input data is used instead. Requires std.
+ pub fn run_all_tests(&self) {
+ self.consistency(&Self::DEFAULT_INPUT);
+ self.consistency(&[0u8; 0]);
+ self.produces_same_state(&Self::DEFAULT_INPUT);
+
+ // Following test requires std.
+ self.incremental_processing_with_leftover();
+
+ self.incremental_and_one_shot(&Self::DEFAULT_INPUT);
+ self.double_finalize_with_reset_no_update_ok(&Self::DEFAULT_INPUT);
+ self.double_finalize_with_reset_ok(&Self::DEFAULT_INPUT);
+ self.double_finalize_err(&Self::DEFAULT_INPUT);
+ self.update_after_finalize_with_reset_ok(&Self::DEFAULT_INPUT);
+ self.update_after_finalize_err(&Self::DEFAULT_INPUT);
+ self.double_reset_ok(&Self::DEFAULT_INPUT);
+ self.immediate_finalize();
+ Self::verify_same_input_ok(&Self::DEFAULT_INPUT);
+ Self::verify_diff_input_err(&Self::DEFAULT_INPUT);
+ }
+
+ #[cfg(not(feature = "safe_api"))]
+ /// Used when quickcheck is not available to generate input.
+ /// Default input data is used instead. Without std.
+ pub fn run_all_tests(&self) {
+ self.consistency(&Self::DEFAULT_INPUT);
+ self.consistency(&[0u8; 0]);
+ self.produces_same_state(&Self::DEFAULT_INPUT);
+ self.incremental_and_one_shot(&Self::DEFAULT_INPUT);
+ self.double_finalize_with_reset_no_update_ok(&Self::DEFAULT_INPUT);
+ self.double_finalize_with_reset_ok(&Self::DEFAULT_INPUT);
+ self.double_finalize_err(&Self::DEFAULT_INPUT);
+ self.update_after_finalize_with_reset_ok(&Self::DEFAULT_INPUT);
+ self.update_after_finalize_err(&Self::DEFAULT_INPUT);
+ self.double_reset_ok(&Self::DEFAULT_INPUT);
+ self.immediate_finalize();
+ Self::verify_same_input_ok(&Self::DEFAULT_INPUT);
+ Self::verify_diff_input_err(&Self::DEFAULT_INPUT);
+ }
+
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Testing different usage combinations of new(), update(),
+ /// finalize() and reset() produce the same output.
+ ///
+ /// It is important to ensure this is also called with empty
+ /// `data`.
+ fn consistency(&self, data: &[u8]) {
+ // new(), update(), finalize()
+ let mut state_1 = self._initial_context.clone();
+ state_1.update(data).unwrap();
+ let res_1 = state_1.finalize().unwrap();
+
+ // new(), reset(), update(), finalize()
+ let mut state_2 = self._initial_context.clone();
+ state_2.reset().unwrap();
+ state_2.update(data).unwrap();
+ let res_2 = state_2.finalize().unwrap();
+
+ // new(), update(), reset(), update(), finalize()
+ let mut state_3 = self._initial_context.clone();
+ state_3.update(data).unwrap();
+ state_3.reset().unwrap();
+ state_3.update(data).unwrap();
+ let res_3 = state_3.finalize().unwrap();
+
+ // new(), update(), finalize(), reset(), update(), finalize()
+ let mut state_4 = self._initial_context.clone();
+ state_4.update(data).unwrap();
+ let _ = state_4.finalize().unwrap();
+ state_4.reset().unwrap();
+ state_4.update(data).unwrap();
+ let res_4 = state_4.finalize().unwrap();
+
+ assert_eq!(res_1, res_2);
+ assert_eq!(res_2, res_3);
+ assert_eq!(res_3, res_4);
+
+ // Tests for the assumption that returning Ok() on empty update() calls
+ // with streaming APIs, gives the correct result. This is done by testing
+ // the reasoning that if update() is empty, returns Ok(), it is the same as
+ // calling new() -> finalize(). i.e not calling update() at all.
+ if data.is_empty() {
+ // new(), finalize()
+ let mut state_5 = self._initial_context.clone();
+ let res_5 = state_5.finalize().unwrap();
+
+ // new(), reset(), finalize()
+ let mut state_6 = self._initial_context.clone();
+ state_6.reset().unwrap();
+ let res_6 = state_6.finalize().unwrap();
+
+ // new(), update(), reset(), finalize()
+ let mut state_7 = self._initial_context.clone();
+ state_7.update(b"WRONG DATA").unwrap();
+ state_7.reset().unwrap();
+ let res_7 = state_7.finalize().unwrap();
+
+ assert_eq!(res_4, res_5);
+ assert_eq!(res_5, res_6);
+ assert_eq!(res_6, res_7);
+ }
+ }
+
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Testing different usage combinations of new(), update(),
+ /// finalize() and reset() produce the same output.
+ fn produces_same_state(&self, data: &[u8]) {
+ // new()
+ let state_1 = self._initial_context.clone();
+
+ // new(), reset()
+ let mut state_2 = self._initial_context.clone();
+ state_2.reset().unwrap();
+
+ // new(), update(), reset()
+ let mut state_3 = self._initial_context.clone();
+ state_3.update(data).unwrap();
+ state_3.reset().unwrap();
+
+ // new(), update(), finalize(), reset()
+ let mut state_4 = self._initial_context.clone();
+ state_4.update(data).unwrap();
+ let _ = state_4.finalize().unwrap();
+ state_4.reset().unwrap();
+
+ T::compare_states(&state_1, &state_2);
+ T::compare_states(&state_2, &state_3);
+ T::compare_states(&state_3, &state_4);
+ }
+
+ #[cfg(feature = "safe_api")]
+ /// Test for issues when incrementally processing data
+ /// with leftover in the internal buffer. It should produce
+ /// the same results as processing the same data in a single pass.
+ fn incremental_processing_with_leftover(&self) {
+ for len in 0..self.blocksize * 4 {
+ let data = vec![0u8; len];
+ let mut state = self._initial_context.clone();
+ let mut other_data: Vec<u8> = Vec::new();
+
+ other_data.extend_from_slice(&data);
+ state.update(&data).unwrap();
+
+ if data.len() > self.blocksize {
+ other_data.extend_from_slice(b"");
+ state.update(b"").unwrap();
+ }
+ if data.len() > self.blocksize * 2 {
+ other_data.extend_from_slice(b"Extra");
+ state.update(b"Extra").unwrap();
+ }
+ if data.len() > self.blocksize * 3 {
+ other_data.extend_from_slice(&[0u8; 256]);
+ state.update(&[0u8; 256]).unwrap();
+ }
+
+ let streaming_result = state.finalize().unwrap();
+ let one_shot_result = T::one_shot(&other_data).unwrap();
+
+ assert_eq!(streaming_result, one_shot_result);
+ }
+ }
+
+ /// new(), update(), finalize() == one_shot()
+ fn incremental_and_one_shot(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let streaming_result = state.finalize().unwrap();
+ let one_shot_result = T::one_shot(data).unwrap();
+
+ assert_eq!(streaming_result, one_shot_result);
+ }
+
+ /// new(), update(), finalize(), reset(), finalize(): OK
+ fn double_finalize_with_reset_no_update_ok(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ state.reset().unwrap();
+ assert!(state.finalize().is_ok());
+ }
+
+ /// new(), update(), finalize(), reset(), update(), finalize(): OK
+ fn double_finalize_with_reset_ok(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ state.reset().unwrap();
+ state.update(data).unwrap();
+ assert!(state.finalize().is_ok());
+ }
+
+ /// new(), update(), finalize(), finalize(): ERR
+ fn double_finalize_err(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ assert!(state.finalize().is_err());
+ }
+
+ /// new(), update(), finalize(), reset(), update(): OK
+ fn update_after_finalize_with_reset_ok(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ state.reset().unwrap();
+ assert!(state.update(data).is_ok());
+ }
+
+ /// Related bug: https://github.com/orion-rs/orion/issues/28
+ /// new(), update(), finalize(), update(): ERR
+ fn update_after_finalize_err(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ assert!(state.update(data).is_err());
+ }
+
+ /// reset(), reset(): OK
+ fn double_reset_ok(&self, data: &[u8]) {
+ let mut state = self._initial_context.clone();
+ state.update(data).unwrap();
+ let _ = state.finalize().unwrap();
+ state.reset().unwrap();
+ assert!(state.reset().is_ok());
+ }
+
+ /// new(), finalize(): OK
+ fn immediate_finalize(&self) {
+ let mut state = self._initial_context.clone();
+ assert!(state.finalize().is_ok());
+ }
+
+ /// Using the same input should always result in a successful verification.
+ pub fn verify_same_input_ok(data: &[u8]) {
+ let expected = T::one_shot(data).unwrap();
+ assert!(T::verify_result(&expected, data).is_ok());
+ }
+
+ /// Using different input should result in a failed verification.
+ pub fn verify_diff_input_err(data: &[u8]) {
+ let expected = T::one_shot(data).unwrap();
+ assert!(T::verify_result(&expected, b"Bad data").is_err());
+ }
+}
diff --git a/vendor/orion/src/test_framework/mod.rs b/vendor/orion/src/test_framework/mod.rs
new file mode 100644
index 0000000..afe9361
--- /dev/null
+++ b/vendor/orion/src/test_framework/mod.rs
@@ -0,0 +1,30 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+/// Tests for a streaming context that offers incremental processing.
+pub mod incremental_interface;
+
+/// Tests for AEAD interfaces such as `chacha20poly1305`.
+pub mod aead_interface;
+
+/// Tests for stream ciphers such as `chacha20`.
+pub mod streamcipher_interface;
diff --git a/vendor/orion/src/test_framework/streamcipher_interface.rs b/vendor/orion/src/test_framework/streamcipher_interface.rs
new file mode 100644
index 0000000..d46e202
--- /dev/null
+++ b/vendor/orion/src/test_framework/streamcipher_interface.rs
@@ -0,0 +1,305 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+#![allow(non_snake_case)]
+
+#[cfg(feature = "safe_api")]
+use crate::errors::UnknownCryptoError;
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+pub trait TestingRandom {
+ /// Randomly generate self.
+ fn gen() -> Self;
+}
+
+#[cfg(feature = "safe_api")]
+/// Test runner for stream ciphers.
+pub fn StreamCipherTestRunner<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: Encryptor,
+ decryptor: Decryptor,
+ key: Key,
+ nonce: Nonce,
+ counter: u32,
+ input: &[u8],
+ expected_ct: Option<&[u8]>,
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ if !input.is_empty() {
+ encrypt_decrypt_out_length(&encryptor, &decryptor, &key, &nonce, input);
+ encrypt_decrypt_equals_expected(
+ &encryptor,
+ &decryptor,
+ &key,
+ &nonce,
+ counter,
+ input,
+ expected_ct,
+ );
+ }
+
+ encrypt_decrypt_input_empty(&encryptor, &decryptor, &key, &nonce);
+ initial_counter_overflow_err(&encryptor, &decryptor, &key, &nonce);
+ initial_counter_max_ok(&encryptor, &decryptor, &key, &nonce);
+}
+
+#[cfg(feature = "safe_api")]
+/// Given a input length `a` find out how many times
+/// the initial counter on encrypt()/decrypt() would
+/// increase.
+fn counter_increase_times(a: f32) -> u32 {
+ // Otherwise a overflowing subtraction would happen
+ if a <= 64f32 {
+ return 0;
+ }
+
+ let check_with_floor = (a / 64f32).floor();
+ let actual = a / 64f32;
+
+ assert!(actual >= check_with_floor);
+ // Subtract one because the first 64 in length
+ // the counter does not increase
+ if actual > check_with_floor {
+ (actual.ceil() as u32) - 1
+ } else {
+ (actual as u32) - 1
+ }
+}
+
+#[cfg(feature = "safe_api")]
+fn return_if_counter_will_overflow<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+ counter: u32,
+ input: &[u8],
+) -> bool
+where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ assert!(!input.is_empty());
+ let mut dst_out = vec![0u8; input.len()];
+
+ // Overflow will occur and the operation should fail
+ let enc_res = encryptor(key, nonce, counter, &[0u8; 0], &mut dst_out).is_err();
+ let dec_res = decryptor(key, nonce, counter, &[0u8; 0], &mut dst_out).is_err();
+
+ enc_res && dec_res
+}
+
+#[cfg(feature = "safe_api")]
+fn encrypt_decrypt_input_empty<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let mut dst_out = [0u8; 64];
+ assert!(encryptor(key, nonce, 0, &[0u8; 0], &mut dst_out).is_err());
+ assert!(decryptor(key, nonce, 0, &[0u8; 0], &mut dst_out).is_err());
+}
+
+#[cfg(feature = "safe_api")]
+fn encrypt_decrypt_out_length<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+ input: &[u8],
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ assert!(!input.is_empty());
+
+ let mut dst_out_empty = vec![0u8; 0];
+ assert!(encryptor(key, nonce, 0, input, &mut dst_out_empty).is_err());
+ assert!(decryptor(key, nonce, 0, input, &mut dst_out_empty).is_err());
+
+ let mut dst_out_less = vec![0u8; input.len() - 1];
+ assert!(encryptor(key, nonce, 0, input, &mut dst_out_less).is_err());
+ assert!(decryptor(key, nonce, 0, input, &mut dst_out_less).is_err());
+
+ let mut dst_out_exact = vec![0u8; input.len()];
+ assert!(encryptor(key, nonce, 0, input, &mut dst_out_exact).is_ok());
+ assert!(decryptor(key, nonce, 0, input, &mut dst_out_exact).is_ok());
+
+ let mut dst_out_greater = vec![0u8; input.len() + 1];
+ assert!(encryptor(key, nonce, 0, input, &mut dst_out_greater).is_ok());
+ assert!(decryptor(key, nonce, 0, input, &mut dst_out_greater).is_ok());
+}
+
+#[cfg(feature = "safe_api")]
+/// Test that encrypting and decrypting produces expected plaintext/ciphertext.
+fn encrypt_decrypt_equals_expected<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+ counter: u32,
+ input: &[u8],
+ expected_ct: Option<&[u8]>,
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ assert!(!input.is_empty());
+
+ // Check if the counter would overflow. If yes, ensure that both encryptor and
+ // decryptor returned errors.
+ if counter_increase_times(input.len() as f32)
+ .checked_add(counter)
+ .is_none()
+ {
+ assert!(return_if_counter_will_overflow(
+ encryptor, decryptor, key, nonce, counter, input
+ ));
+
+ return;
+ }
+
+ let mut dst_out_ct = vec![0u8; input.len()];
+ encryptor(key, nonce, counter, input, &mut dst_out_ct).unwrap();
+ if let Some(expected_result) = expected_ct {
+ assert_eq!(expected_result, &dst_out_ct[..]);
+ }
+
+ let mut dst_out_pt = vec![0u8; input.len()];
+ decryptor(key, nonce, counter, &dst_out_ct, &mut dst_out_pt).unwrap();
+ assert_eq!(input, &dst_out_pt[..]);
+ if let Some(expected_result) = expected_ct {
+ decryptor(key, nonce, counter, expected_result, &mut dst_out_pt).unwrap();
+ assert_eq!(input, &dst_out_pt[..]);
+ }
+}
+
+#[cfg(feature = "safe_api")]
+/// Test that a initial counter will not overflow the internal.
+fn initial_counter_overflow_err<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let mut dst_out = [0u8; 128];
+ assert!(encryptor(
+ key,
+ nonce,
+ u32::MAX,
+ &[0u8; 65], // CHACHA_BLOCKSIZE + 1 one to trigger internal block counter addition.
+ &mut dst_out
+ )
+ .is_err());
+ assert!(decryptor(
+ key,
+ nonce,
+ u32::MAX,
+ &[0u8; 65], // CHACHA_BLOCKSIZE + 1 one to trigger internal block counter addition.
+ &mut dst_out
+ )
+ .is_err());
+}
+
+#[cfg(feature = "safe_api")]
+/// Test that processing one block does not fail on the largest possible initial block counter.
+fn initial_counter_max_ok<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+ key: &Key,
+ nonce: &Nonce,
+) where
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let mut dst_out = [0u8; 64];
+ assert!(encryptor(
+ key,
+ nonce,
+ u32::MAX,
+ &[0u8; 64], // Only needs to process one keystream
+ &mut dst_out
+ )
+ .is_ok());
+ assert!(decryptor(
+ key,
+ nonce,
+ u32::MAX,
+ &[0u8; 64], // Only needs to process one keystream
+ &mut dst_out
+ )
+ .is_ok());
+}
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+/// Test that encrypting using different secret-key/nonce/initial-counter combinations yields different
+/// ciphertexts.
+pub fn test_diff_params_diff_output<Encryptor, Decryptor, Key, Nonce>(
+ encryptor: &Encryptor,
+ decryptor: &Decryptor,
+) where
+ Key: TestingRandom + PartialEq<Key>,
+ Nonce: TestingRandom + PartialEq<Nonce>,
+ Encryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+ Decryptor: Fn(&Key, &Nonce, u32, &[u8], &mut [u8]) -> Result<(), UnknownCryptoError>,
+{
+ let input = &[0u8; 16];
+
+ let sk1 = Key::gen();
+ let sk2 = Key::gen();
+ assert!(sk1 != sk2);
+
+ let n1 = Nonce::gen();
+ let n2 = Nonce::gen();
+ assert!(n1 != n2);
+
+ let c1 = 0u32;
+ let c2 = 1u32;
+
+ let mut dst_out_ct = vec![0u8; input.len()];
+ let mut dst_out_pt = vec![0u8; input.len()];
+
+ // Different secret key
+ encryptor(&sk1, &n1, c1, input, &mut dst_out_ct).unwrap();
+ decryptor(&sk2, &n1, c1, &dst_out_ct, &mut dst_out_pt).unwrap();
+ assert_ne!(&dst_out_pt[..], input);
+
+ // Different nonce
+ encryptor(&sk1, &n1, c1, input, &mut dst_out_ct).unwrap();
+ decryptor(&sk1, &n2, c1, &dst_out_ct, &mut dst_out_pt).unwrap();
+ assert_ne!(&dst_out_pt[..], input);
+
+ // Different initial counter
+ encryptor(&sk1, &n1, c1, input, &mut dst_out_ct).unwrap();
+ decryptor(&sk1, &n1, c2, &dst_out_ct, &mut dst_out_pt).unwrap();
+ assert_ne!(&dst_out_pt[..], input);
+}
diff --git a/vendor/orion/src/typedefs.rs b/vendor/orion/src/typedefs.rs
new file mode 100644
index 0000000..6471c30
--- /dev/null
+++ b/vendor/orion/src/typedefs.rs
@@ -0,0 +1,993 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+///
+/// Trait implementation macros
+
+#[cfg(feature = "safe_api")]
+/// Macro that implements the `Default` trait using a CSPRNG.
+macro_rules! impl_default_trait (($name:ident, $size:expr) => (
+ impl Default for $name {
+ #[cfg(feature = "safe_api")]
+ /// Randomly generate using a CSPRNG with recommended size. Not available in `no_std` context.
+ fn default() -> $name {
+ let mut value = vec![0u8; $size];
+ crate::util::secure_rand_bytes(&mut value).unwrap();
+
+ $name { value, original_length: $size }
+ }
+ }
+));
+
+/// Macro that implements the `PartialEq` trait on a object called `$name` that
+/// provides a given $bytes_function to return a slice. This `PartialEq` will
+/// execute in constant-time.
+///
+/// This also provides an empty `Eq` implementation.
+macro_rules! impl_ct_partialeq_trait (($name:ident, $bytes_function:ident) => (
+ impl PartialEq<$name> for $name {
+ fn eq(&self, other: &$name) -> bool {
+ use subtle::ConstantTimeEq;
+
+ (self.$bytes_function()
+ .ct_eq(other.$bytes_function())).into()
+ }
+ }
+
+ impl Eq for $name {}
+
+ impl PartialEq<&[u8]> for $name {
+ fn eq(&self, other: &&[u8]) -> bool {
+ use subtle::ConstantTimeEq;
+
+ (self.$bytes_function()
+ .ct_eq(*other)).into()
+ }
+ }
+));
+
+/// Macro that implements the `Debug` trait on a object called `$name`.
+/// This `Debug` will omit any fields of object `$name` to avoid them being
+/// written to logs.
+macro_rules! impl_omitted_debug_trait (($name:ident) => (
+ impl core::fmt::Debug for $name {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{} {{***OMITTED***}}", stringify!($name))
+ }
+ }
+));
+
+/// Macro that implements the `Debug` trait on a object called `$name`.
+macro_rules! impl_normal_debug_trait (($name:ident) => (
+ impl core::fmt::Debug for $name {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{} {:?}", stringify!($name), &self.value[..])
+ }
+ }
+));
+
+/// Macro that implements the `serde::{Serialize, Deserialize}` traits.
+#[cfg(feature = "serde")]
+macro_rules! impl_serde_traits (($name:ident, $bytes_function:ident) => (
+
+ #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+ /// This type tries to serialize as a `&[u8]` would. Note that the serialized
+ /// type likely does not have the same protections that Orion provides, such
+ /// as constant-time operations. A good rule of thumb is to only serialize
+ /// these types for storage. Don't operate on the serialized types.
+ impl serde::Serialize for $name {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::ser::Serializer,
+ {
+ let bytes: &[u8] = &self.$bytes_function();
+ bytes.serialize(serializer)
+ }
+ }
+
+ #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+ /// This type tries to deserialize as a `Vec<u8>` would. If it succeeds, the digest
+ /// will be built using `Self::from_slice`.
+ ///
+ /// Note that **this allocates** once to store the referenced bytes on the heap.
+ impl<'de> serde::Deserialize<'de> for $name {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::de::Deserializer<'de>,
+ {
+ let bytes = Vec::<u8>::deserialize(deserializer)?;
+ std::convert::TryFrom::try_from(bytes.as_slice()).map_err(serde::de::Error::custom)
+ }
+ }
+));
+
+/// Macro that implements the `Drop` trait on a object called `$name` which has
+/// a field `value`. This `Drop` will zero out the field `value` when the
+/// objects destructor is called.
+macro_rules! impl_drop_trait (($name:ident) => (
+ impl Drop for $name {
+ fn drop(&mut self) {
+ use zeroize::Zeroize;
+ self.value.iter_mut().zeroize();
+ }
+ }
+));
+
+/// Macro that implements the `AsRef<[u8]>` trait on a object called `$name`
+/// which has fields `value` and `original_length`. This will return the inner
+/// `value` as a byte slice, and should only be implemented on public types
+/// which don't have any special protections.
+macro_rules! impl_asref_trait (($name:ident) => (
+ impl AsRef<[u8]> for $name {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.value[..self.original_length].as_ref()
+ }
+ }
+));
+
+/// Macro that implements the `From<[T]>` trait on a object called `$name`
+/// which has fields `value` and `original_length`. It implements From
+/// based on `$size` and this macro should, in most cases, only be used for
+/// types which have a fixed-length.
+macro_rules! impl_from_trait (($name:ident, $size:expr) => (
+ impl From<[u8; $size]> for $name {
+ #[inline]
+ /// Make an object from a byte array.
+ fn from(bytes: [u8; $size]) -> $name {
+ $name {
+ value: bytes,
+ original_length: $size
+ }
+ }
+ }
+));
+
+/// Macro that implements `TryFrom<&[u8]>` on an object called `$name` that
+/// implements the method `from_slice`.
+macro_rules! impl_try_from_trait (($name:ident) => (
+ /// Delegates to `from_slice` implementation
+ impl TryFrom<&[u8]> for $name {
+ type Error = UnknownCryptoError;
+ fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
+ Self::from_slice(slice)
+ }
+ }
+));
+
+///
+/// Function implementation macros
+
+/// Macro to implement a `from_slice()` function. Returns `UnknownCryptoError`
+/// if the slice length is not accepted.
+/// $lower_bound and $upper_bound is the inclusive range of which a slice might
+/// be acceptable in length. If a slice may only be a fixed size, $lower_bound
+/// and $upper_bound should be the same. The `value` field will always be allocated with
+/// a size of $upper_bound.
+macro_rules! func_from_slice (($name:ident, $lower_bound:expr, $upper_bound:expr) => (
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from a given byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<$name, UnknownCryptoError> {
+
+ let slice_len = slice.len();
+
+ if !($lower_bound..=$upper_bound).contains(&slice_len) {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut value = [0u8; $upper_bound];
+ value[..slice_len].copy_from_slice(slice);
+
+ Ok($name { value, original_length: slice_len })
+ }
+));
+
+#[cfg(feature = "safe_api")]
+/// Macro to implement a `from_slice()` function. Returns `UnknownCryptoError`
+/// if the slice is empty.
+macro_rules! func_from_slice_variable_size (($name:ident) => (
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ #[cfg(feature = "safe_api")]
+ /// Construct from a given byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<$name, UnknownCryptoError> {
+ // See issue on `isize` limit: https://github.com/orion-rs/orion/issues/130
+ if slice.is_empty() || slice.len() > (isize::MAX as usize) {
+ return Err(UnknownCryptoError);
+ }
+
+ Ok($name { value: Vec::from(slice), original_length: slice.len() })
+ }
+));
+
+/// Macro to implement a `unprotected_as_bytes()` function for objects that
+/// implement extra protections. Typically used on objects that implement
+/// `Drop`.
+macro_rules! func_unprotected_as_bytes (() => (
+ #[inline]
+ /// Return the object as byte slice. __**Warning**__: Should not be used unless strictly
+ /// needed. This __**breaks protections**__ that the type implements.
+ pub fn unprotected_as_bytes(&self) -> &[u8] {
+ self.value[..self.original_length].as_ref()
+ }
+));
+
+/// Macro to implement a `len()` function which will return the original_length
+/// field. Meaning the amount of bytes the newtype was created from.
+macro_rules! func_len (() => (
+ #[inline]
+ /// Return the length of the object.
+ pub fn len(&self) -> usize {
+ self.original_length
+ }
+));
+
+/// Macro to implement an `is_empty()` function which will return `true` if `self.len() == 0`.
+macro_rules! func_is_empty (() => (
+ #[inline]
+ /// Return `true` if this object does not hold any data, `false` otherwise.
+ ///
+ /// __NOTE__: This method should always return `false`, since there shouldn't be a way
+ /// to create an empty instance of this object.
+ pub fn is_empty(&self) -> bool {
+ self.original_length == 0
+ }
+));
+
+/// Macro to implement a `generate()` function for objects that benefit from
+/// having a CSPRNG available to generate data of a fixed length $gen_length.
+macro_rules! func_generate (($name:ident, $upper_bound:expr, $gen_length:expr) => (
+ #[cfg(feature = "safe_api")]
+ /// Randomly generate using a CSPRNG. Not available in `no_std` context.
+ pub fn generate() -> $name {
+ let mut value = [0u8; $upper_bound];
+ // This will not panic on size, unless the newtype has been defined with $upper_bound
+ // or $gen_length equal to 0.
+ crate::util::secure_rand_bytes(&mut value[..$gen_length]).unwrap();
+
+ $name { value, original_length: $gen_length }
+ }
+));
+
+#[cfg(feature = "safe_api")]
+/// Macro to implement a `generate()` function for objects that benefit from
+/// having a CSPRNG available to generate data of a variable length.
+macro_rules! func_generate_variable_size (($name:ident) => (
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ #[cfg(feature = "safe_api")]
+ /// Randomly generate using a CSPRNG. Not available in `no_std` context.
+ pub fn generate(length: usize) -> Result<$name, UnknownCryptoError> {
+ // See issue on `isize` limit: https://github.com/orion-rs/orion/issues/130
+ if length < 1 || length > (isize::MAX as usize) {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut value = vec![0u8; length];
+ // This cannot panic on size input due to above length checks.
+ crate::util::secure_rand_bytes(&mut value).unwrap();
+
+ Ok($name { value, original_length: length })
+ }
+));
+
+///
+/// Test implementation macros
+
+#[cfg(test)]
+#[cfg(feature = "serde")]
+macro_rules! test_serde_impls (($name:ident, $gen_length:expr) => (
+ #[test]
+ fn test_serde_serialized_equivalence_to_bytes_fn() {
+ let bytes = &[38u8; $gen_length][..];
+ let orion_type = $name::from_slice(bytes).unwrap();
+ let serialized_from_bytes = serde_json::to_value(bytes).unwrap();
+ let serialized_from_orion_type = serde_json::to_value(&orion_type).unwrap();
+ assert_eq!(serialized_from_bytes, serialized_from_orion_type);
+ }
+
+ #[test]
+ fn test_serde_deserialized_equivalence_to_bytes_fn() {
+ let bytes = &[38u8; $gen_length][..];
+ let serialized_from_bytes = serde_json::to_value(bytes).unwrap();
+ let orion_type: $name = serde_json::from_value(serialized_from_bytes).unwrap();
+ assert_eq!(orion_type, bytes);
+ }
+));
+
+#[cfg(test)]
+macro_rules! test_bound_parameters (($name:ident, $lower_bound:expr, $upper_bound:expr, $gen_length:expr) => (
+ #[test]
+ fn test_bound_params() {
+ // $lower_bound:
+ assert!($lower_bound <= $upper_bound);
+ // $upper_bound:
+ // $gen_length:
+ assert!($gen_length <= $upper_bound);
+ assert!($gen_length >= $lower_bound);
+ }
+));
+
+#[cfg(test)]
+macro_rules! test_partial_eq (($name:ident, $upper_bound:expr) => (
+ #[test]
+ fn test_partial_eq() {
+ // PartialEq<Self>
+ assert_eq!($name::from_slice(&[0u8; $upper_bound]).unwrap(), $name::from_slice(&[0u8; $upper_bound]).unwrap());
+ assert_ne!($name::from_slice(&[0u8; $upper_bound]).unwrap(), $name::from_slice(&[1u8; $upper_bound]).unwrap());
+ // PartialEq<&[u8]>
+ assert_eq!($name::from_slice(&[0u8; $upper_bound]).unwrap(), [0u8; $upper_bound].as_ref());
+ assert_ne!($name::from_slice(&[0u8; $upper_bound]).unwrap(), [1u8; $upper_bound].as_ref());
+ }
+));
+
+#[cfg(test)]
+macro_rules! test_from_slice (($name:ident, $lower_bound:expr, $upper_bound:expr) => (
+ #[test]
+ fn test_from_slice() {
+ assert!($name::from_slice(&[0u8; $upper_bound]).is_ok());
+ assert!($name::from_slice(&[0u8; $lower_bound]).is_ok());
+
+ assert!($name::from_slice(&[0u8; $upper_bound + 1]).is_err());
+ assert!($name::from_slice(&[0u8; $lower_bound - 1]).is_err());
+ assert!($name::from_slice(&[0u8; 0]).is_err());
+
+ // Test non-fixed-length definitions
+ if $upper_bound != $lower_bound {
+ assert!($name::from_slice(&[0u8; $upper_bound - 1]).is_ok());
+ assert!($name::from_slice(&[0u8; $lower_bound + 1]).is_ok());
+ }
+ }
+));
+
+#[cfg(test)]
+macro_rules! test_as_bytes_and_get_length (($name:ident, $lower_bound:expr, $upper_bound:expr, $bytes_function:ident) => (
+ #[test]
+ fn test_as_bytes() {
+ let test_upper = $name::from_slice(&[0u8; $upper_bound]).unwrap();
+ let test_lower = $name::from_slice(&[0u8; $lower_bound]).unwrap();
+
+ assert_eq!(test_upper.$bytes_function().len(), test_upper.len());
+ assert_eq!(test_upper.len(), $upper_bound);
+
+ assert_eq!(test_lower.$bytes_function().len(), test_lower.len());
+ assert_eq!(test_lower.len(), $lower_bound);
+
+ assert_eq!(test_upper.is_empty(), false);
+ assert_eq!(test_lower.is_empty(), false);
+
+ // Test non-fixed-length definitions
+ if $lower_bound != $upper_bound {
+ let test_upper = $name::from_slice(&[0u8; $upper_bound - 1]).unwrap();
+ let test_lower = $name::from_slice(&[0u8; $lower_bound + 1]).unwrap();
+
+ assert_eq!(test_upper.$bytes_function().len(), test_upper.len());
+ assert_eq!(test_upper.len(), $upper_bound - 1);
+
+ assert_eq!(test_lower.$bytes_function().len(), test_lower.len());
+ assert_eq!(test_lower.len(), $lower_bound + 1);
+
+ assert_eq!(test_upper.is_empty(), false);
+ assert_eq!(test_lower.is_empty(), false);
+ }
+ }
+));
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+macro_rules! test_generate (($name:ident, $gen_length:expr) => (
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_generate() {
+ let test_zero = $name::from_slice(&[0u8; $gen_length]).unwrap();
+ // A random one should never be all 0's.
+ let test_rand = $name::generate();
+ assert_ne!(test_zero, test_rand);
+ // A random generated one should always be $gen_length in length.
+ assert_eq!(test_rand.len(), $gen_length);
+ }
+));
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+macro_rules! test_omitted_debug (($name:ident, $upper_bound:expr) => (
+ #[test]
+ #[cfg(feature = "safe_api")]
+ // format! is only available with std
+ fn test_omitted_debug() {
+ let secret = format!("{:?}", [0u8; $upper_bound].as_ref());
+ let test_debug_contents = format!("{:?}", $name::from_slice(&[0u8; $upper_bound]).unwrap());
+ assert_eq!(test_debug_contents.contains(&secret), false);
+ }
+));
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+macro_rules! test_normal_debug (($name:ident, $upper_bound:expr) => (
+ #[test]
+ #[cfg(feature = "safe_api")]
+ // format! is only available with std
+ fn test_normal_debug() {
+ let public = format!("{:?}", [0u8; $upper_bound].as_ref());
+ let test_debug_contents = format!("{:?}", $name::from_slice(&[0u8; $upper_bound]).unwrap());
+ assert_eq!(test_debug_contents.contains(&public), true);
+ }
+));
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+macro_rules! test_from_slice_variable (($name:ident) => (
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_from_slice_variable() {
+ assert!($name::from_slice(&[0u8; 512]).is_ok());
+ assert!($name::from_slice(&[0u8; 256]).is_ok());
+ assert!($name::from_slice(&[0u8; 1]).is_ok());
+ assert!($name::from_slice(&[0u8; 0]).is_err());
+ }
+));
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+macro_rules! test_generate_variable (($name:ident) => (
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_generate_variable() {
+ assert!($name::generate(0).is_err());
+ assert!($name::generate((isize::MAX as usize) + 1).is_err());
+ assert!($name::generate(1).is_ok());
+ assert!($name::generate(64).is_ok());
+
+ let test_zero = $name::from_slice(&[0u8; 128]).unwrap();
+ // A random one should never be all 0's.
+ let test_rand = $name::generate(128).unwrap();
+ assert_ne!(test_zero, test_rand);
+ assert_eq!(test_rand.len(), 128);
+ }
+));
+
+///
+/// Newtype implementation macros
+
+/// Macro to construct a type containing sensitive data, using a fixed-size
+/// array.
+///
+/// - $name: The name for the newtype.
+///
+/// - $test_module_name: The name for the newtype's testing module (usually
+/// "test_$name").
+///
+/// - $lower_bound/$upper_bound: An inclusive range that defines what length a
+/// secret value might be. Used to validate length of `slice` in from_slice().
+/// $upper_bound also defines the `value` field array allocation size.
+///
+/// - $gen_length: The amount of data to be randomly generated when using
+/// generate().
+macro_rules! construct_secret_key {
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $lower_bound:expr, $upper_bound:expr)) => (
+ $(#[$meta])*
+ ///
+ /// # Security:
+ /// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+ /// that the type implements.
+ ///
+ /// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+ /// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+ /// is implemented in such a way that the comparison happens in constant time. Thus, users should
+ /// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+ /// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+ /// ```rust
+ /// # #[cfg(feature = "safe_api")] {
+ /// use orion::hazardous::stream::chacha20::SecretKey;
+ ///
+ /// // Initialize a secret key with random bytes.
+ /// let secret_key = SecretKey::generate();
+ ///
+ /// // Secure, constant-time comparison with a byte slice
+ /// assert_ne!(secret_key, &[0; 32][..]);
+ ///
+ /// // Secure, constant-time comparison with another SecretKey
+ /// assert_ne!(secret_key, SecretKey::generate());
+ /// # }
+ /// # Ok::<(), orion::errors::UnknownCryptoError>(())
+ /// ```
+ pub struct $name {
+ value: [u8; $upper_bound],
+ original_length: usize,
+ }
+
+ impl_omitted_debug_trait!($name);
+ impl_drop_trait!($name);
+ impl_ct_partialeq_trait!($name, unprotected_as_bytes);
+
+ impl $name {
+ func_from_slice!($name, $lower_bound, $upper_bound);
+ func_unprotected_as_bytes!();
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+
+ test_bound_parameters!($name, $lower_bound, $upper_bound, $upper_bound);
+ test_from_slice!($name, $lower_bound, $upper_bound);
+ test_as_bytes_and_get_length!($name, $lower_bound, $upper_bound, unprotected_as_bytes);
+ test_partial_eq!($name, $upper_bound);
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_omitted_debug!($name, $upper_bound);
+ }
+ }
+ );
+
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $lower_bound:expr, $upper_bound:expr, $gen_length:expr)) => (
+ $(#[$meta])*
+ ///
+ /// # Security:
+ /// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+ /// that the type implements.
+ ///
+ /// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+ /// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+ /// is implemented in such a way that the comparison happens in constant time. Thus, users should
+ /// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+ /// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+ /// ```rust
+ /// # #[cfg(feature = "safe_api")] {
+ /// use orion::hazardous::stream::chacha20::SecretKey;
+ ///
+ /// // Initialize a secret key with random bytes.
+ /// let secret_key = SecretKey::generate();
+ ///
+ /// // Secure, constant-time comparison with a byte slice
+ /// assert_ne!(secret_key, &[0; 32][..]);
+ ///
+ /// // Secure, constant-time comparison with another SecretKey
+ /// assert_ne!(secret_key, SecretKey::generate());
+ /// # }
+ /// # Ok::<(), orion::errors::UnknownCryptoError>(())
+ /// ```
+ pub struct $name {
+ value: [u8; $upper_bound],
+ original_length: usize,
+ }
+
+ impl_omitted_debug_trait!($name);
+ impl_drop_trait!($name);
+ impl_ct_partialeq_trait!($name, unprotected_as_bytes);
+
+ impl $name {
+ func_from_slice!($name, $lower_bound, $upper_bound);
+ func_unprotected_as_bytes!();
+ func_generate!($name, $upper_bound, $gen_length);
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+
+ test_bound_parameters!($name, $lower_bound, $upper_bound, $gen_length);
+ test_from_slice!($name, $lower_bound, $upper_bound);
+ test_as_bytes_and_get_length!($name, $lower_bound, $upper_bound, unprotected_as_bytes);
+ test_partial_eq!($name, $upper_bound);
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_generate!($name, $gen_length);
+ test_omitted_debug!($name, $upper_bound);
+ }
+ }
+ );
+}
+
+/// Macro to construct a public type containing non-sensitive data, using a
+/// fixed-size array.
+///
+/// - $name: The name for the newtype.
+///
+/// - $test_module_name: The name for the newtype's testing module (usually
+/// "test_$name").
+///
+/// - $lower_bound/$upper_bound: An inclusive range that defines what length a
+/// public value might be. Used to validate length of `slice` in from_slice().
+/// $upper_bound also defines the `value` field array allocation size.
+///
+/// - $gen_length: The amount of data to be randomly generated when using
+/// generate(). If not supplied, the public newtype will not have a
+/// `generate()` function available.
+macro_rules! construct_public {
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $lower_bound:expr, $upper_bound:expr)) => (
+ #[derive(Clone, Copy)]
+ $(#[$meta])*
+ ///
+ pub struct $name {
+ pub(crate) value: [u8; $upper_bound],
+ original_length: usize,
+ }
+
+ impl_ct_partialeq_trait!($name, as_ref);
+ impl_normal_debug_trait!($name);
+ impl_try_from_trait!($name);
+ impl_asref_trait!($name);
+
+ #[cfg(feature = "serde")]
+ impl_serde_traits!($name, as_ref);
+
+ impl $name {
+ func_from_slice!($name, $lower_bound, $upper_bound);
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+ // Replace $gen_length with $upper_bound since this doesn't have
+ // generate() function.
+ test_bound_parameters!($name, $lower_bound, $upper_bound, $upper_bound);
+ test_from_slice!($name, $lower_bound, $upper_bound);
+ test_as_bytes_and_get_length!($name, $lower_bound, $upper_bound, as_ref);
+ test_partial_eq!($name, $upper_bound);
+
+ #[cfg(feature = "serde")]
+ test_serde_impls!($name, $upper_bound);
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_normal_debug!($name, $upper_bound);
+ }
+ }
+ );
+
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $lower_bound:expr, $upper_bound:expr, $gen_length:expr)) => (
+ #[derive(Clone, Copy)]
+ $(#[$meta])*
+ ///
+ pub struct $name {
+ pub(crate) value: [u8; $upper_bound],
+ original_length: usize,
+ }
+
+ impl_ct_partialeq_trait!($name, as_ref);
+ impl_normal_debug_trait!($name);
+ impl_try_from_trait!($name);
+ impl_asref_trait!($name);
+
+ #[cfg(feature = "serde")]
+ impl_serde_traits!($name, as_ref);
+
+ impl $name {
+ func_from_slice!($name, $lower_bound, $upper_bound);
+ func_generate!($name, $upper_bound, $gen_length);
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+ test_bound_parameters!($name, $lower_bound, $upper_bound, $upper_bound);
+ test_from_slice!($name, $lower_bound, $upper_bound);
+ test_as_bytes_and_get_length!($name, $lower_bound, $upper_bound, as_ref);
+ test_partial_eq!($name, $upper_bound);
+
+ #[cfg(feature = "serde")]
+ test_serde_impls!($name, $upper_bound);
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_normal_debug!($name, $upper_bound);
+ test_generate!($name, $gen_length);
+ }
+ }
+ );
+}
+
+/// Macro to construct a tag type that MACs return.
+macro_rules! construct_tag {
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $lower_bound:expr, $upper_bound:expr)) => (
+ #[derive(Clone)]
+ $(#[$meta])*
+ ///
+ /// # Security:
+ /// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+ /// that the type implements.
+ ///
+ /// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+ /// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+ /// is implemented in such a way that the comparison happens in constant time. Thus, users should
+ /// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+ /// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+ /// ```rust
+ /// use orion::hazardous::mac::hmac::sha512::Tag;
+ ///
+ /// // Initialize an arbitrary, 64-byte tag.
+ /// let tag = Tag::from_slice(&[1; 64])?;
+ ///
+ /// // Secure, constant-time comparison with a byte slice
+ /// assert_eq!(tag, &[1; 64][..]);
+ ///
+ /// // Secure, constant-time comparison with another Tag
+ /// assert_eq!(tag, Tag::from_slice(&[1; 64])?);
+ /// # Ok::<(), orion::errors::UnknownCryptoError>(())
+ /// ```
+ pub struct $name {
+ value: [u8; $upper_bound],
+ original_length: usize,
+ }
+
+ impl_omitted_debug_trait!($name);
+ impl_drop_trait!($name);
+ impl_ct_partialeq_trait!($name, unprotected_as_bytes);
+ impl_try_from_trait!($name);
+
+ #[cfg(feature = "serde")]
+ impl_serde_traits!($name, unprotected_as_bytes);
+
+ impl $name {
+ func_from_slice!($name, $lower_bound, $upper_bound);
+ func_unprotected_as_bytes!();
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+ // Replace $gen_length with $upper_bound since a tag doesn't have
+ // generate() function.
+ test_bound_parameters!($name, $lower_bound, $upper_bound, $upper_bound);
+ test_from_slice!($name, $lower_bound, $upper_bound);
+ test_as_bytes_and_get_length!($name, $lower_bound, $upper_bound, unprotected_as_bytes);
+ test_partial_eq!($name, $upper_bound);
+
+ #[cfg(feature = "serde")]
+ test_serde_impls!($name, $upper_bound);
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_omitted_debug!($name, $upper_bound);
+ }
+ }
+ );
+}
+
+/// Macro to construct a secret key used for HMAC. This pre-pads the given key
+/// to the required length specified by the HMAC specifications.
+macro_rules! construct_hmac_key {
+ ($(#[$meta:meta])*
+ ($name:ident, $sha2:ident, $sha2_outsize:expr, $test_module_name:ident, $size:expr)) => (
+ $(#[$meta])*
+ ///
+ /// # Security:
+ /// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+ /// that the type implements.
+ ///
+ /// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+ /// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+ /// is implemented in such a way that the comparison happens in constant time. Thus, users should
+ /// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+ /// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+ /// ```rust
+ /// # #[cfg(feature = "safe_api")] {
+ /// use orion::hazardous::mac::hmac::sha512::SecretKey;
+ ///
+ /// // Initialize a secret key with random bytes.
+ /// let secret_key = SecretKey::generate();
+ ///
+ /// // Secure, constant-time comparison with a byte slice
+ /// assert_ne!(secret_key, &[0; 32][..]);
+ ///
+ /// // Secure, constant-time comparison with another SecretKey
+ /// assert_ne!(secret_key, SecretKey::generate());
+ /// # }
+ /// # Ok::<(), orion::errors::UnknownCryptoError>(())
+ /// ```
+ pub struct $name {
+ value: [u8; $size],
+ original_length: usize,
+ }
+
+ impl_omitted_debug_trait!($name);
+ impl_drop_trait!($name);
+ impl_ct_partialeq_trait!($name, unprotected_as_bytes);
+
+ impl $name {
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Construct from a given byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<$name, UnknownCryptoError> {
+ let mut secret_key = [0u8; $size];
+
+ let slice_len = slice.len();
+
+ if slice_len > $size {
+ secret_key[..$sha2_outsize].copy_from_slice(&$sha2::digest(slice)?.as_ref());
+ } else {
+ secret_key[..slice_len].copy_from_slice(slice);
+ }
+
+ Ok($name { value: secret_key, original_length: $size })
+ }
+
+ func_unprotected_as_bytes!();
+ func_generate!($name, $size, $size);
+ func_len!();
+ func_is_empty!();
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+ test_as_bytes_and_get_length!($name, $size, $size, unprotected_as_bytes);
+ test_partial_eq!($name, $size);
+
+ #[test]
+ fn test_key_size() {
+ assert!($name::from_slice(&[0u8; $size]).is_ok());
+ assert!($name::from_slice(&[0u8; $size - $size]).is_ok());
+ assert!($name::from_slice(&[0u8; $size + 1]).is_ok());
+ }
+
+ #[cfg(test)]
+ #[cfg(feature = "safe_api")]
+ mod tests_with_std {
+ use super::*;
+
+ test_generate!($name, $size);
+ test_omitted_debug!($name, $size);
+ }
+ }
+ );
+}
+
+#[cfg(feature = "safe_api")]
+/// Macro to construct a type containing sensitive data which is stored on the
+/// heap.
+macro_rules! construct_secret_key_variable_size {
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $default_size:expr)) => (
+ #[cfg(feature = "safe_api")]
+ $(#[$meta])*
+ ///
+ /// # Security:
+ /// - __**Avoid using**__ `unprotected_as_bytes()` whenever possible, as it breaks all protections
+ /// that the type implements.
+ ///
+ /// - The trait `PartialEq<&'_ [u8]>` is implemented for this type so that users are not tempted
+ /// to call `unprotected_as_bytes` to compare this sensitive value to a byte slice. The trait
+ /// is implemented in such a way that the comparison happens in constant time. Thus, users should
+ /// prefer `SecretType == &[u8]` over `SecretType.unprotected_as_bytes() == &[u8]`.
+ /// Examples are shown below. The examples apply to any type that implements `PartialEq<&'_ [u8]>`.
+ /// ```rust
+ /// # #[cfg(feature = "safe_api")] {
+ /// use orion::pwhash::Password;
+ ///
+ /// // Initialize a password with 32 random bytes.
+ /// let password = Password::generate(32)?;
+ ///
+ /// // Secure, constant-time comparison with a byte slice
+ /// assert_ne!(password, &[0; 32][..]);
+ ///
+ /// // Secure, constant-time comparison with another Password
+ /// assert_ne!(password, Password::generate(32)?);
+ /// # }
+ /// # Ok::<(), orion::errors::UnknownCryptoError>(())
+ /// ```
+ pub struct $name {
+ pub(crate) value: Vec<u8>,
+ original_length: usize,
+ }
+
+ impl_omitted_debug_trait!($name);
+ impl_drop_trait!($name);
+ impl_ct_partialeq_trait!($name, unprotected_as_bytes);
+ impl_default_trait!($name, $default_size);
+
+ impl $name {
+ func_from_slice_variable_size!($name);
+ func_unprotected_as_bytes!();
+ func_len!();
+ func_is_empty!();
+ func_generate_variable_size!($name);
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+
+ test_from_slice_variable!($name);
+ test_as_bytes_and_get_length!($name, 1, $default_size + 1, unprotected_as_bytes);
+ test_generate_variable!($name);
+ test_omitted_debug!($name, $default_size);
+ test_partial_eq!($name, $default_size);
+ }
+ );
+}
+
+#[cfg(feature = "safe_api")]
+/// Macro to construct a type containing non-sensitive which is stored on the
+/// heap.
+macro_rules! construct_salt_variable_size {
+ ($(#[$meta:meta])*
+ ($name:ident, $test_module_name:ident, $default_size:expr)) => (
+ #[cfg(feature = "safe_api")]
+ $(#[$meta])*
+ ///
+ pub struct $name {
+ value: Vec<u8>,
+ original_length: usize,
+ }
+
+ impl_normal_debug_trait!($name);
+ impl_default_trait!($name, $default_size);
+ impl_ct_partialeq_trait!($name, as_ref);
+ impl_asref_trait!($name);
+ impl_try_from_trait!($name);
+
+ #[cfg(feature = "serde")]
+ impl_serde_traits!($name, as_ref);
+
+ impl $name {
+ func_from_slice_variable_size!($name);
+ func_len!();
+ func_is_empty!();
+ func_generate_variable_size!($name);
+ }
+
+ #[cfg(test)]
+ mod $test_module_name {
+ use super::*;
+
+ test_from_slice_variable!($name);
+ test_as_bytes_and_get_length!($name, 1, $default_size + 1, as_ref);
+ test_generate_variable!($name);
+ test_partial_eq!($name, $default_size);
+ test_normal_debug!($name, $default_size);
+
+ #[cfg(feature = "serde")]
+ test_serde_impls!($name, $default_size);
+ }
+ );
+}
diff --git a/vendor/orion/src/util/endianness.rs b/vendor/orion/src/util/endianness.rs
new file mode 100644
index 0000000..b8d0d92
--- /dev/null
+++ b/vendor/orion/src/util/endianness.rs
@@ -0,0 +1,371 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+use core::convert::TryInto;
+use core::mem;
+
+macro_rules! impl_store_into {
+ ($type_alias:ty, $conv_function:ident, $func_name:ident) => {
+ /// Store bytes in `src` in `dst`.
+ pub fn $func_name(src: &[$type_alias], dst: &mut [u8]) {
+ let type_alias_len = mem::size_of::<$type_alias>();
+ // The length of src must be evenly divisible with the length of dst,
+ // making sure .chunks_exact() leaves no remainder.
+ assert_eq!(mem::size_of_val(src), dst.len());
+
+ for (src_elem, dst_chunk) in src.iter().zip(dst.chunks_exact_mut(type_alias_len)) {
+ dst_chunk.copy_from_slice(&src_elem.$conv_function());
+ }
+ }
+ };
+}
+
+macro_rules! impl_load_into {
+ ($type_alias:ty, $type_alias_expr:ident, $conv_function:ident, $func_name:ident) => {
+ /// Load bytes in `src` into `dst`.
+ pub fn $func_name(src: &[u8], dst: &mut [$type_alias]) {
+ let type_alias_len = mem::size_of::<$type_alias>();
+ // The length of src must be evenly divisible with the length of dst,
+ // making sure .chunks_exact() leaves no remainder.
+ assert_eq!(mem::size_of_val(dst), src.len());
+
+ for (src_chunk, dst_elem) in src.chunks_exact(type_alias_len).zip(dst.iter_mut()) {
+ // The above assert and this debug assert should prove that .unwrap()
+ // cannot panic using TryInto.
+ debug_assert_eq!(src_chunk.len(), type_alias_len);
+ *dst_elem = $type_alias_expr::$conv_function(src_chunk.try_into().unwrap());
+ }
+ }
+ };
+}
+
+macro_rules! impl_load {
+ ($type_alias:ty, $type_alias_expr:ident, $conv_function:ident, $func_name:ident) => {
+ /// Convert bytes in `src` to a given primitive.
+ pub fn $func_name(src: &[u8]) -> $type_alias {
+ // Satisfying this assert should prove that using TryInto
+ // cannot panic.
+ assert_eq!(mem::size_of::<$type_alias>(), src.len());
+ $type_alias_expr::$conv_function(src.try_into().unwrap())
+ }
+ };
+}
+
+impl_load!(u32, u32, from_le_bytes, load_u32_le);
+
+#[cfg(test)]
+impl_load_into!(u32, u32, from_le_bytes, load_u32_into_le);
+
+impl_load_into!(u64, u64, from_le_bytes, load_u64_into_le);
+
+impl_store_into!(u32, to_le_bytes, store_u32_into_le);
+
+#[cfg(any(feature = "safe_api", feature = "alloc", test))]
+impl_store_into!(u64, to_le_bytes, store_u64_into_le);
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ macro_rules! test_empty_src_panic {
+ ($test_name:ident, $src_val:expr, $dst_val:expr, $func_to_test:expr) => {
+ #[test]
+ #[should_panic]
+ fn $test_name() {
+ let mut dst_load = $dst_val;
+ $func_to_test($src_val, &mut dst_load);
+ }
+ };
+ }
+
+ macro_rules! test_dst_length_panic {
+ ($test_name:ident, $src_val:expr, $dst_val:expr, $func_to_test:expr) => {
+ #[test]
+ #[should_panic]
+ fn $test_name() {
+ let mut dst_load = $dst_val;
+ $func_to_test($src_val, &mut dst_load);
+ }
+ };
+ }
+
+ macro_rules! test_dst_length_ok {
+ ($test_name:ident, $src_val:expr, $dst_val:expr, $func_to_test:expr) => {
+ #[test]
+ fn $test_name() {
+ let mut dst_load = $dst_val;
+ $func_to_test($src_val, &mut dst_load);
+ }
+ };
+ }
+
+ test_empty_src_panic! {test_panic_empty_load_u32_le, &[0u8; 0], [0u32; 4], load_u32_into_le}
+ test_empty_src_panic! {test_panic_empty_load_u64_le, &[0u8; 0], [0u64; 4], load_u64_into_le}
+
+ test_empty_src_panic! {test_panic_empty_store_u32_le, &[0u32; 0], [0u8; 24], store_u32_into_le}
+ test_empty_src_panic! {test_panic_empty_store_u64_le, &[0u64; 0], [0u8; 24], store_u64_into_le}
+
+ // -1 too low
+ test_dst_length_panic! {test_dst_length_load_u32_le_low, &[0u8; 64], [0u32; 15], load_u32_into_le}
+ test_dst_length_panic! {test_dst_length_load_u64_le_low, &[0u8; 64], [0u64; 7], load_u64_into_le}
+
+ test_dst_length_panic! {test_dst_length_store_u32_le_low, &[0u32; 15], [0u8; 64], store_u32_into_le}
+ test_dst_length_panic! {test_dst_length_store_u64_le_low, &[0u64; 7], [0u8; 64], store_u64_into_le}
+
+ // +1 too high
+ test_dst_length_panic! {test_dst_length_load_u32_le_high, &[0u8; 64], [0u32; 17], load_u32_into_le}
+ test_dst_length_panic! {test_dst_length_load_u64_le_high, &[0u8; 64], [0u64; 9], load_u64_into_le}
+
+ test_dst_length_panic! {test_dst_length_store_u32_le_high, &[0u32; 17], [0u8; 64], store_u32_into_le}
+ test_dst_length_panic! {test_dst_length_store_u64_le_high, &[0u64; 9], [0u8; 64], store_u64_into_le}
+
+ // Ok
+ test_dst_length_ok! {test_dst_length_load_u32_le_ok, &[0u8; 64], [0u32; 16], load_u32_into_le}
+ test_dst_length_ok! {test_dst_length_load_u64_le_ok, &[0u8; 64], [0u64; 8], load_u64_into_le}
+
+ test_dst_length_ok! {test_dst_length_store_u32_le_ok, &[0u32; 16], [0u8; 64], store_u32_into_le}
+ test_dst_length_ok! {test_dst_length_store_u64_le_ok, &[0u64; 8], [0u8; 64], store_u64_into_le}
+
+ #[test]
+ #[should_panic]
+ fn test_load_single_src_high() {
+ load_u32_le(&[0u8; 5]);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_load_single_src_low() {
+ load_u32_le(&[0u8; 3]);
+ }
+
+ #[test]
+ fn test_load_single_src_ok() {
+ load_u32_le(&[0u8; 4]);
+ }
+
+ #[test]
+ fn test_results_store_and_load_u32_into_le() {
+ let input_0: [u32; 2] = [777190791, 1465409568];
+ let input_1: [u32; 4] = [3418616323, 2289579672, 172726903, 1048927929];
+ let input_2: [u32; 6] = [
+ 84693101, 443297962, 3962861724, 3081916164, 4167874952, 3982893227,
+ ];
+ let input_3: [u32; 8] = [
+ 2761719494, 242571916, 3097304063, 3924274282, 1553851098, 3673278295, 3531531406,
+ 2347852690,
+ ];
+
+ let expected_0: [u8; 8] = [135, 253, 82, 46, 32, 96, 88, 87];
+ let expected_1: [u8; 16] = [
+ 3, 242, 195, 203, 152, 54, 120, 136, 119, 154, 75, 10, 185, 94, 133, 62,
+ ];
+ let expected_2: [u8; 24] = [
+ 109, 80, 12, 5, 170, 48, 108, 26, 156, 120, 52, 236, 4, 79, 178, 183, 136, 185, 108,
+ 248, 171, 32, 102, 237,
+ ];
+ let expected_3: [u8; 32] = [
+ 198, 126, 156, 164, 140, 90, 117, 14, 255, 27, 157, 184, 106, 172, 231, 233, 218, 226,
+ 157, 92, 87, 199, 241, 218, 142, 228, 126, 210, 146, 99, 241, 139,
+ ];
+
+ let mut actual_bytes_0 = [0u8; 8];
+ let mut actual_bytes_1 = [0u8; 16];
+ let mut actual_bytes_2 = [0u8; 24];
+ let mut actual_bytes_3 = [0u8; 32];
+
+ store_u32_into_le(&input_0, &mut actual_bytes_0);
+ store_u32_into_le(&input_1, &mut actual_bytes_1);
+ store_u32_into_le(&input_2, &mut actual_bytes_2);
+ store_u32_into_le(&input_3, &mut actual_bytes_3);
+
+ assert_eq!(actual_bytes_0, expected_0);
+ assert_eq!(actual_bytes_1, expected_1);
+ assert_eq!(actual_bytes_2, expected_2);
+ assert_eq!(actual_bytes_3, expected_3);
+
+ let mut actual_nums_0 = [0u32; 2];
+ let mut actual_nums_1 = [0u32; 4];
+ let mut actual_nums_2 = [0u32; 6];
+ let mut actual_nums_3 = [0u32; 8];
+
+ load_u32_into_le(&actual_bytes_0, &mut actual_nums_0);
+ load_u32_into_le(&actual_bytes_1, &mut actual_nums_1);
+ load_u32_into_le(&actual_bytes_2, &mut actual_nums_2);
+ load_u32_into_le(&actual_bytes_3, &mut actual_nums_3);
+
+ assert_eq!(actual_nums_0, input_0);
+ assert_eq!(actual_nums_1, input_1);
+ assert_eq!(actual_nums_2, input_2);
+ assert_eq!(actual_nums_3, input_3);
+ }
+
+ #[test]
+ fn test_results_store_and_load_u64_into_le() {
+ let input_0: [u64; 2] = [3449173576222258260, 2574723713182514848];
+ let input_1: [u64; 4] = [
+ 18418572897904167042,
+ 8576666536239673655,
+ 11410394363908906546,
+ 7465319841649779999,
+ ];
+ let input_2: [u64; 6] = [
+ 9356732802025012686,
+ 185726711773006573,
+ 11478604380402216982,
+ 11229612629557120299,
+ 2892361689551487626,
+ 11014300370630005317,
+ ];
+ let input_3: [u64; 8] = [
+ 9519534723912119720,
+ 6001603601558183532,
+ 8164850737304360888,
+ 571607234094878696,
+ 4752095875230140457,
+ 13190954815003641110,
+ 16657196750477544576,
+ 10329042493888204415,
+ ];
+
+ let expected_0: [u8; 16] = [
+ 84, 52, 100, 211, 23, 237, 221, 47, 160, 190, 4, 95, 147, 65, 187, 35,
+ ];
+ let expected_1: [u8; 32] = [
+ 130, 8, 55, 1, 119, 234, 155, 255, 55, 177, 139, 9, 198, 112, 6, 119, 50, 222, 232, 23,
+ 56, 221, 89, 158, 31, 229, 53, 208, 215, 36, 154, 103,
+ ];
+ let expected_2: [u8; 48] = [
+ 206, 61, 242, 202, 232, 202, 217, 129, 237, 10, 136, 216, 117, 213, 147, 2, 22, 240,
+ 29, 35, 222, 49, 76, 159, 43, 13, 254, 133, 48, 153, 215, 155, 138, 66, 170, 219, 161,
+ 187, 35, 40, 69, 210, 218, 176, 212, 167, 218, 152,
+ ];
+ let expected_3: [u8; 64] = [
+ 168, 53, 199, 13, 101, 46, 28, 132, 108, 158, 148, 129, 173, 250, 73, 83, 184, 215, 28,
+ 129, 124, 96, 79, 113, 232, 207, 68, 59, 192, 193, 238, 7, 41, 8, 177, 85, 5, 214, 242,
+ 65, 22, 69, 133, 252, 131, 175, 15, 183, 128, 76, 1, 226, 48, 64, 42, 231, 127, 14, 31,
+ 46, 108, 33, 88, 143,
+ ];
+
+ let mut actual_bytes_0 = [0u8; 16];
+ let mut actual_bytes_1 = [0u8; 32];
+ let mut actual_bytes_2 = [0u8; 48];
+ let mut actual_bytes_3 = [0u8; 64];
+
+ store_u64_into_le(&input_0, &mut actual_bytes_0);
+ store_u64_into_le(&input_1, &mut actual_bytes_1);
+ store_u64_into_le(&input_2, &mut actual_bytes_2);
+ store_u64_into_le(&input_3, &mut actual_bytes_3);
+
+ assert_eq!(actual_bytes_0, expected_0);
+ assert_eq!(actual_bytes_1, expected_1);
+ assert_eq!(actual_bytes_2.as_ref(), expected_2.as_ref());
+ assert_eq!(actual_bytes_3.as_ref(), expected_3.as_ref());
+
+ let mut actual_nums_0 = [0u64; 2];
+ let mut actual_nums_1 = [0u64; 4];
+ let mut actual_nums_2 = [0u64; 6];
+ let mut actual_nums_3 = [0u64; 8];
+
+ load_u64_into_le(&actual_bytes_0, &mut actual_nums_0);
+ load_u64_into_le(&actual_bytes_1, &mut actual_nums_1);
+ load_u64_into_le(&actual_bytes_2, &mut actual_nums_2);
+ load_u64_into_le(&actual_bytes_3, &mut actual_nums_3);
+
+ assert_eq!(actual_nums_0, input_0);
+ assert_eq!(actual_nums_1, input_1);
+ assert_eq!(actual_nums_2, input_2);
+ assert_eq!(actual_nums_3, input_3);
+ }
+
+ #[test]
+ fn test_results_load_u32() {
+ let input_0: [u8; 4] = [203, 12, 195, 63];
+ let expected_0: u32 = 1069747403;
+
+ assert_eq!(load_u32_le(&input_0), expected_0);
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Load and store should not change the result.
+ fn prop_load_store_u32_le(src: Vec<u8>) -> bool {
+ if !src.is_empty() && src.len() % 4 == 0 {
+ let mut dst_load = vec![0u32; src.len() / 4];
+ load_u32_into_le(&src[..], &mut dst_load);
+ // Test that loading a single also is working correctly
+ dst_load[0] = load_u32_le(&src[..4]);
+ let mut dst_store = src.clone();
+ store_u32_into_le(&dst_load[..], &mut dst_store);
+
+ dst_store == src
+ } else {
+ // Otherwise above functions panic.
+ true
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Load and store should not change the result.
+ fn prop_load_store_u64_le(src: Vec<u8>) -> bool {
+ if !src.is_empty() && src.len() % 8 == 0 {
+ let mut dst_load = vec![0u64; src.len() / 8];
+ load_u64_into_le(&src[..], &mut dst_load);
+ let mut dst_store = src.clone();
+ store_u64_into_le(&dst_load[..], &mut dst_store);
+
+ dst_store == src
+ } else {
+ // Otherwise above functions panic.
+ true
+ }
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Store and load should not change the result.
+ fn prop_store_load_u32_le(src: Vec<u32>) -> bool {
+ let mut dst_store = vec![0u8; src.len() * 4];
+ store_u32_into_le(&src[..], &mut dst_store);
+ let mut dst_load = src.clone();
+ load_u32_into_le(&dst_store[..], &mut dst_load);
+ if dst_store.len() >= 4 {
+ // Test that loading a single also is working correctly
+ dst_load[0] = load_u32_le(&dst_store[..4]);
+ }
+
+ dst_load == src
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Store and load should not change the result.
+ fn prop_store_load_u64_le(src: Vec<u64>) -> bool {
+ let mut dst_store = vec![0u8; src.len() * 8];
+ store_u64_into_le(&src[..], &mut dst_store);
+ let mut dst_load = src.clone();
+ load_u64_into_le(&dst_store[..], &mut dst_load);
+
+ dst_load == src
+ }
+}
diff --git a/vendor/orion/src/util/mod.rs b/vendor/orion/src/util/mod.rs
new file mode 100644
index 0000000..27fc291
--- /dev/null
+++ b/vendor/orion/src/util/mod.rs
@@ -0,0 +1,186 @@
+// MIT License
+
+// Copyright (c) 2018-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.
+
+use crate::errors;
+use subtle::ConstantTimeEq;
+
+/// xor_slices!(src, destination): XOR $src into $destination slice.
+/// Uses iter() and .zip(), so it short-circuits on the slice that has
+/// the smallest length.
+macro_rules! xor_slices {
+ ($src:expr, $destination:expr) => {
+ for (inplace, _src_elem) in $destination.iter_mut().zip($src.iter()) {
+ *inplace ^= _src_elem;
+ }
+ };
+}
+
+pub(crate) mod endianness;
+pub(crate) mod u32x4;
+pub(crate) mod u64x4;
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+#[cfg(feature = "safe_api")]
+/// Generate random bytes using a CSPRNG. Not available in `no_std` context.
+///
+/// # About:
+/// This function can be used to generate cryptographic keys, salts or other
+/// values that rely on strong randomness. Please note that most keys and other
+/// types used throughout Orion, implement their own `generate()` function and
+/// it is strongly preferred to use those, compared to [`secure_rand_bytes()`].
+///
+/// This uses [`getrandom`].
+///
+/// # Parameters:
+/// - `dst`: Destination buffer for the randomly generated bytes. The amount of
+/// bytes to be generated is
+/// implied by the length of `dst`.
+///
+/// # Errors:
+/// An error will be returned if:
+/// - `dst` is empty.
+///
+/// # Panics:
+/// A panic will occur if:
+/// - Failure to generate random bytes securely.
+/// - The platform is not supported by [`getrandom`].
+///
+/// # Example:
+/// ```rust
+/// use orion::util;
+///
+/// let mut salt = [0u8; 64];
+/// util::secure_rand_bytes(&mut salt)?;
+/// # Ok::<(), orion::errors::UnknownCryptoError>(())
+/// ```
+/// [`getrandom`]: https://github.com/rust-random/getrandom
+pub fn secure_rand_bytes(dst: &mut [u8]) -> Result<(), errors::UnknownCryptoError> {
+ if dst.is_empty() {
+ return Err(errors::UnknownCryptoError);
+ }
+
+ getrandom::getrandom(dst).unwrap();
+
+ Ok(())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// Compare two equal length slices in constant time.
+///
+/// # About:
+/// Compare two equal length slices, in constant time, using the
+/// [subtle](https://github.com/dalek-cryptography/subtle) crate.
+///
+/// # Parameters:
+/// - `a`: The first slice used in the comparison.
+/// - `b`: The second slice used in the comparison.
+///
+/// # Errors:
+/// An error will be returned if:
+/// - `a` and `b` do not have the same length.
+/// - `a` is not equal to `b`.
+///
+/// # Example:
+/// ```rust
+/// # #[cfg(feature = "safe_api")] {
+/// use orion::util;
+///
+/// let mut rnd_bytes = [0u8; 64];
+/// assert!(util::secure_cmp(&rnd_bytes, &[0u8; 64]).is_ok());
+///
+/// util::secure_rand_bytes(&mut rnd_bytes)?;
+/// assert!(util::secure_cmp(&rnd_bytes, &[0u8; 64]).is_err());
+/// # }
+/// # Ok::<(), orion::errors::UnknownCryptoError>(())
+/// ```
+pub fn secure_cmp(a: &[u8], b: &[u8]) -> Result<(), errors::UnknownCryptoError> {
+ if a.ct_eq(b).into() {
+ Ok(())
+ } else {
+ Err(errors::UnknownCryptoError)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[cfg(feature = "safe_api")]
+ #[test]
+ fn rand_key_len_ok() {
+ let mut dst = [0u8; 64];
+ secure_rand_bytes(&mut dst).unwrap();
+ }
+
+ #[cfg(feature = "safe_api")]
+ #[test]
+ fn rand_key_len_error() {
+ let mut dst = [0u8; 0];
+ assert!(secure_rand_bytes(&mut dst).is_err());
+
+ let err = secure_rand_bytes(&mut dst).unwrap_err();
+ assert_eq!(err, errors::UnknownCryptoError);
+ }
+
+ #[test]
+ fn test_ct_eq_ok() {
+ let buf_1 = [0x06; 10];
+ let buf_2 = [0x06; 10];
+
+ assert!(secure_cmp(&buf_1, &buf_2).is_ok());
+ assert!(secure_cmp(&buf_2, &buf_1).is_ok());
+ }
+
+ #[test]
+ fn test_ct_eq_diff_len() {
+ let buf_1 = [0x06; 10];
+ let buf_2 = [0x06; 5];
+
+ assert!(secure_cmp(&buf_1, &buf_2).is_err());
+ assert!(secure_cmp(&buf_2, &buf_1).is_err());
+ }
+
+ #[test]
+ fn test_ct_ne() {
+ let buf_1 = [0x06; 10];
+ let buf_2 = [0x76; 10];
+
+ assert!(secure_cmp(&buf_1, &buf_2).is_err());
+ assert!(secure_cmp(&buf_2, &buf_1).is_err());
+ }
+
+ #[test]
+ fn test_ct_ne_reg() {
+ assert!(secure_cmp(&[0], &[0, 1]).is_err());
+ assert!(secure_cmp(&[0, 1], &[0]).is_err());
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_secure_cmp(a: Vec<u8>, b: Vec<u8>) -> bool {
+ if a == b {
+ secure_cmp(&a, &b).is_ok()
+ } else {
+ secure_cmp(&a, &b).is_err()
+ }
+ }
+}
diff --git a/vendor/orion/src/util/u32x4.rs b/vendor/orion/src/util/u32x4.rs
new file mode 100644
index 0000000..c1ff1bc
--- /dev/null
+++ b/vendor/orion/src/util/u32x4.rs
@@ -0,0 +1,98 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+#[derive(Clone, Copy)]
+pub(crate) struct U32x4(
+ pub(crate) u32,
+ pub(crate) u32,
+ pub(crate) u32,
+ pub(crate) u32,
+);
+
+impl core::ops::BitXor for U32x4 {
+ type Output = Self;
+
+ #[must_use]
+ fn bitxor(self, _rhs: Self) -> Self::Output {
+ Self(
+ self.0 ^ _rhs.0,
+ self.1 ^ _rhs.1,
+ self.2 ^ _rhs.2,
+ self.3 ^ _rhs.3,
+ )
+ }
+}
+
+impl zeroize::Zeroize for U32x4 {
+ fn zeroize(&mut self) {
+ self.0.zeroize();
+ self.1.zeroize();
+ self.2.zeroize();
+ self.3.zeroize();
+ }
+}
+
+impl U32x4 {
+ #[must_use]
+ pub(crate) const fn wrapping_add(self, _rhs: Self) -> Self {
+ Self(
+ self.0.wrapping_add(_rhs.0),
+ self.1.wrapping_add(_rhs.1),
+ self.2.wrapping_add(_rhs.2),
+ self.3.wrapping_add(_rhs.3),
+ )
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_1(self) -> Self {
+ Self(self.1, self.2, self.3, self.0)
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_2(self) -> Self {
+ Self(self.2, self.3, self.0, self.1)
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_3(self) -> Self {
+ Self(self.3, self.0, self.1, self.2)
+ }
+
+ #[must_use]
+ pub(crate) const fn rotate_left(self, n: u32) -> Self {
+ Self(
+ self.0.rotate_left(n),
+ self.1.rotate_left(n),
+ self.2.rotate_left(n),
+ self.3.rotate_left(n),
+ )
+ }
+
+ pub(crate) fn store_into_le(&self, slice_in: &mut [u8]) {
+ debug_assert_eq!(slice_in.len(), core::mem::size_of::<u32>() * 4);
+ let mut iter = slice_in.chunks_exact_mut(core::mem::size_of::<u32>());
+ iter.next().unwrap().copy_from_slice(&self.0.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.1.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.2.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.3.to_le_bytes());
+ }
+}
diff --git a/vendor/orion/src/util/u64x4.rs b/vendor/orion/src/util/u64x4.rs
new file mode 100644
index 0000000..bc181c4
--- /dev/null
+++ b/vendor/orion/src/util/u64x4.rs
@@ -0,0 +1,114 @@
+// MIT License
+
+// Copyright (c) 2019-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.
+
+#[derive(Clone, Copy, Default)]
+pub(crate) struct U64x4(
+ pub(crate) u64,
+ pub(crate) u64,
+ pub(crate) u64,
+ pub(crate) u64,
+);
+
+impl core::ops::BitXor for U64x4 {
+ type Output = Self;
+
+ #[must_use]
+ fn bitxor(self, _rhs: Self) -> Self::Output {
+ Self(
+ self.0 ^ _rhs.0,
+ self.1 ^ _rhs.1,
+ self.2 ^ _rhs.2,
+ self.3 ^ _rhs.3,
+ )
+ }
+}
+
+impl core::ops::BitXorAssign for U64x4 {
+ fn bitxor_assign(&mut self, _rhs: Self) {
+ self.0 ^= _rhs.0;
+ self.1 ^= _rhs.1;
+ self.2 ^= _rhs.2;
+ self.3 ^= _rhs.3;
+ }
+}
+
+impl zeroize::Zeroize for U64x4 {
+ fn zeroize(&mut self) {
+ self.0.zeroize();
+ self.1.zeroize();
+ self.2.zeroize();
+ self.3.zeroize();
+ }
+}
+
+#[cfg(test)]
+impl PartialEq<U64x4> for U64x4 {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0 && self.1 == other.1 && self.2 == other.2 && self.3 == other.3
+ }
+}
+
+impl U64x4 {
+ #[must_use]
+ pub(crate) const fn wrapping_add(self, _rhs: Self) -> Self {
+ Self(
+ self.0.wrapping_add(_rhs.0),
+ self.1.wrapping_add(_rhs.1),
+ self.2.wrapping_add(_rhs.2),
+ self.3.wrapping_add(_rhs.3),
+ )
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_1(self) -> Self {
+ Self(self.1, self.2, self.3, self.0)
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_2(self) -> Self {
+ Self(self.2, self.3, self.0, self.1)
+ }
+
+ #[must_use]
+ pub(crate) const fn shl_3(self) -> Self {
+ Self(self.3, self.0, self.1, self.2)
+ }
+
+ #[must_use]
+ pub(crate) const fn rotate_right(self, n: u32) -> Self {
+ Self(
+ self.0.rotate_right(n),
+ self.1.rotate_right(n),
+ self.2.rotate_right(n),
+ self.3.rotate_right(n),
+ )
+ }
+
+ pub(crate) fn store_into_le(self, slice_in: &mut [u8]) {
+ debug_assert_eq!(slice_in.len(), core::mem::size_of::<u64>() * 4);
+ let mut iter = slice_in.chunks_exact_mut(core::mem::size_of::<u64>());
+ iter.next().unwrap().copy_from_slice(&self.0.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.1.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.2.to_le_bytes());
+ iter.next().unwrap().copy_from_slice(&self.3.to_le_bytes());
+ }
+}