/// Value of the domain separation byte "D" used by XofTurboShake128 when invoking TurboSHAKE128. const XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION: u8 = 1; /// Value of the domain separation byte "D" used by XofFixedKeyAes128 when invoking TurboSHAKE128. #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] const XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION: u8 = 2;
usecrate::{
field::FieldElement,
prng::Prng,
vdaf::{CodecError, Decode, Encode},
}; #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] use aes::{
cipher::{generic_array::GenericArray, BlockEncrypt, KeyInit},
Block,
}; #[cfg(feature = "crypto-dependencies")] use aes::{
cipher::{KeyIvInit, StreamCipher},
Aes128,
}; #[cfg(feature = "crypto-dependencies")] use ctr::Ctr64BE; #[cfg(feature = "crypto-dependencies")] use hmac::{Hmac, Mac}; use rand_core::{
impls::{next_u32_via_fill, next_u64_via_fill},
RngCore, SeedableRng,
}; #[cfg(feature = "crypto-dependencies")] use sha2::Sha256; use sha3::{
digest::{ExtendableOutput, Update, XofReader},
TurboShake128, TurboShake128Core, TurboShake128Reader,
}; #[cfg(feature = "crypto-dependencies")] use std::fmt::Formatter; use std::{
fmt::Debug,
io::{Cursor, Read},
}; use subtle::{Choice, ConstantTimeEq};
/// Trait for deriving a vector of field elements. pubtrait IntoFieldVec: RngCore + Sized { /// Generate a finite field vector from the seed stream. fn into_field_vec<F: FieldElement>(self, length: usize) -> Vec<F>;
}
impl<S: RngCore> IntoFieldVec for S { fn into_field_vec<F: FieldElement>(self, length: usize) -> Vec<F> {
Prng::from_seed_stream(self).take(length).collect()
}
}
/// An extendable output function (XOF) with the interface specified in [[draft-irtf-cfrg-vdaf-08]]. /// /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ pubtrait Xof<const SEED_SIZE: usize>: Clone + Debug { /// The type of stream produced by this XOF. type SeedStream: RngCore + Sized;
/// Construct an instance of [`Xof`] with the given seed. fn init(seed_bytes: &[u8; SEED_SIZE], dst: &[u8]) -> Self;
/// Update the XOF state by passing in the next fragment of the info string. The final info /// string is assembled from the concatenation of sequence of fragments passed to this method. fn update(&mutself, data: &[u8]);
/// Finalize the XOF state, producing a seed stream. fn into_seed_stream(self) -> Self::SeedStream;
/// Construct a seed stream from the given seed and info string. fn seed_stream(seed: &Seed<SEED_SIZE>, dst: &[u8], binder: &[u8]) -> Self::SeedStream { letmut xof = Self::init(seed.as_ref(), dst);
xof.update(binder);
xof.into_seed_stream()
}
}
/// The key stream produced by AES128 in CTR-mode. #[cfg(feature = "crypto-dependencies")] #[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))] pubstruct SeedStreamAes128(Ctr64BE<Aes128>);
#[cfg(feature = "crypto-dependencies")] impl SeedStreamAes128 { /// Construct an instance of the seed stream with the given AES key `key` and initialization /// vector `iv`. pubfn new(key: &[u8], iv: &[u8]) -> Self {
SeedStreamAes128(<Ctr64BE<Aes128> as KeyIvInit>::new(key.into(), iv.into()))
}
/// The XOF based on TurboSHAKE128 as specified in [[draft-irtf-cfrg-vdaf-08]]. /// /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[derive(Clone, Debug)] pubstruct XofTurboShake128(TurboShake128);
impl Xof<16> for XofTurboShake128 { type SeedStream = SeedStreamTurboShake128;
fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self { letmut xof = Self(TurboShake128::from_core(TurboShake128Core::new(
XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION,
)));
Update::update(
&mut xof.0,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
);
Update::update(&mut xof.0, dst);
Update::update(&mut xof.0, seed_bytes);
xof
}
/// A `rand`-compatible interface to construct XofTurboShake128 seed streams, with the domain /// separation tag and binder string both fixed as the empty string. impl SeedableRng for SeedStreamTurboShake128 { type Seed = [u8; 16];
/// Factory to produce multiple [`XofFixedKeyAes128`] instances with the same fixed key and /// different seeds. #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[cfg_attr(
docsrs,
doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
)] pubstruct XofFixedKeyAes128Key {
cipher: Aes128,
}
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] impl XofFixedKeyAes128Key { /// Derive the fixed key from the domain separation tag and binder string. pubfn new(dst: &[u8], binder: &[u8]) -> Self { letmut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new(
XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION,
));
Update::update(
&mut fixed_key_deriver,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
);
Update::update(&mut fixed_key_deriver, dst);
Update::update(&mut fixed_key_deriver, binder); letmut key = GenericArray::from([0; 16]);
XofReader::read(&mut fixed_key_deriver.finalize_xof(), key.as_mut()); Self {
cipher: Aes128::new(&key),
}
}
/// Combine a fixed key with a seed to produce a new stream of bytes. pubfn with_seed(&self, seed: &[u8; 16]) -> SeedStreamFixedKeyAes128 {
SeedStreamFixedKeyAes128 {
cipher: self.cipher.clone(),
base_block: (*seed).into(),
length_consumed: 0,
}
}
}
/// XofFixedKeyAes128 as specified in [[draft-irtf-cfrg-vdaf-08]]. This XOF is NOT RECOMMENDED for /// general use; see Section 9 ("Security Considerations") for details. /// /// This XOF combines TurboSHAKE128 and a fixed-key mode of operation for AES-128. The key is /// "fixed" in the sense that it is derived (using TurboSHAKE128) from the domain separation tag and /// binder strings, and depending on the application, these strings can be hard-coded. The seed is /// used to construct each block of input passed to a hash function built from AES-128. /// /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/ #[derive(Clone, Debug)] #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] #[cfg_attr(
docsrs,
doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
)] pubstruct XofFixedKeyAes128 {
fixed_key_deriver: TurboShake128,
base_block: Block,
}
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))] impl Xof<16> for XofFixedKeyAes128 { type SeedStream = SeedStreamFixedKeyAes128;
fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self { letmut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new(2u8));
Update::update(
&mut fixed_key_deriver,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
);
Update::update(&mut fixed_key_deriver, dst); Self {
fixed_key_deriver,
base_block: (*seed_bytes).into(),
}
}
// NOTE(cjpatton) We might be able to speed this up by unrolling this loop and encrypting // multiple blocks at the same time via `self.cipher.encrypt_blocks()`. for block_counter inself.length_consumed / 16..(next_length_consumed + 15) / 16 {
block.clone_from(&self.base_block); for (b, i) in block.iter_mut().zip(block_counter.to_le_bytes().iter()) {
*b ^= i;
} self.hash_block(&mut block); let read = std::cmp::min(16 - offset, buf.len() - index);
buf[index..index + read].copy_from_slice(&block[offset..offset + read]);
offset = 0;
index += read;
}
/// XOF based on HMAC-SHA256 and AES128. This XOF is not part of the VDAF spec. #[cfg(feature = "crypto-dependencies")] #[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))] #[derive(Clone, Debug)] pubstruct XofHmacSha256Aes128(Hmac<Sha256>);
#[cfg(feature = "crypto-dependencies")] impl Xof<32> for XofHmacSha256Aes128 { type SeedStream = SeedStreamAes128;
fn init(seed_bytes: &[u8; 32], dst: &[u8]) -> Self { letmut mac = <Hmac<Sha256> as Mac>::new_from_slice(seed_bytes).unwrap();
Mac::update(
&mut mac,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
);
Mac::update(&mut mac, dst); Self(mac)
}
fn into_seed_stream(self) -> SeedStreamAes128 { let tag = Mac::finalize(self.0).into_bytes(); let (key, iv) = tag.split_at(16);
SeedStreamAes128::new(key, iv)
}
}
#[cfg(test)] mod tests { usesuper::*; usecrate::{field::Field128, vdaf::equality_comparison_test}; use serde::{Deserialize, Serialize}; use std::{convert::TryInto, io::Cursor};
// Test correctness of dervied methods. fn test_xof<P, const SEED_SIZE: usize>() where
P: Xof<SEED_SIZE>,
{ let seed = Seed::generate().unwrap(); let dst = b"algorithm and usage"; let binder = b"bind to artifact";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.