From af309a839c2a2f882c629a66b8eb6c935ee8f4d5 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Thu, 11 Jan 2024 07:42:07 -0800 Subject: [PATCH] Add XofHmacSha256Aes128 An XOF based on HMAC-SHA256 and AES128. This XOF does not appear in the VDAF spec. --- Cargo.toml | 2 +- src/vdaf/test_vec/XofHmacSha256Aes128.json | 8 ++++ src/vdaf/xof.rs | 56 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/vdaf/test_vec/XofHmacSha256Aes128.json diff --git a/Cargo.toml b/Cargo.toml index 48d3f058..74fbec2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ default = ["crypto-dependencies"] experimental = ["bitvec", "fiat-crypto", "fixed", "num-bigint", "num-rational", "num-traits", "num-integer", "num-iter", "rand"] multithreaded = ["rayon"] prio2 = ["crypto-dependencies", "hmac", "sha2"] -crypto-dependencies = ["aes", "ctr"] +crypto-dependencies = ["aes", "ctr", "hmac", "sha2"] test-util = ["hex", "rand", "serde_json"] [workspace] diff --git a/src/vdaf/test_vec/XofHmacSha256Aes128.json b/src/vdaf/test_vec/XofHmacSha256Aes128.json new file mode 100644 index 00000000..510cc539 --- /dev/null +++ b/src/vdaf/test_vec/XofHmacSha256Aes128.json @@ -0,0 +1,8 @@ +{ + "binder": "62696e64657220737472696e67", + "derived_seed": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6", + "dst": "646f6d61696e2073657061726174696f6e20746167", + "expanded_vec_field128": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6172f208e79762fed92c73cea422b312860008ee80e30f31d2d87840890604f39db37983f5c3483407333cecdb1b9ea550c26bc4f2d999fda91963054c6cb35a8ad8d28ee74a48e28aa475d67124e7c4417149955e506690d62e17f0730b7d4db8a9754f80603b7720205819d26bcfe4a4663d05c98c12705ea7dc333d5746d9c8ba697bb3d5be95d26ccb73052cb8fb19edfc35eaebaa22779436d3015512c9b536003d98b04a0f46feddbff762007c377c28a04039f72657650885bd40ed37acea63facd3c33d1ecb5048641053af5b4018b0c373d9ed7440da9fc6c76666c2eb8ed2943a64bbf6dae93ac91fcc26d7225c2ae42349161522fcce0b92d209411af8566b0adbaa36a8479737017efd2c359ea43924cdf432650dcd742e358af55ff6c321d0ebaae2abf5812d58b060cc147395e8137f99db58d2c425f2704da067df3a41c0443918375c177fa53545d8190d828c6045bbe5930e4762588ea14dc0a9db6cd903216ccae968ca0b11f0ac04e4dfc69a99986841dc99c851e314c7d4b10f4ef72e1244b543465fed076a7e9f50baca4ad7dccc73bfc55310f2ae6eaeaf7ee7a4d41fec76bff3b04e67d1f83e4da59f1fcb45877adfc3e4a2b1d5e3f136131ca2a02f34bdba1c5d2dafb2178674dc002d247662497b7f5818880cff308e5222e6df0bcdf6f68ebfaa8d0551530fa00ec29646441961e33b50872ada911591e16e3021baa5e7869756d3d812a63e3c7fa2c0ec2dc4cabe11c0256829b360ad9431536ab96efbe5a364cd1c323de8fbe405a2c87b9c58e5740bfb118af0ca1a23afb4a04e9cec3b9d1e57834cbc0fa17d5d7285f1f013df05e92a7343", + "length": 40, + "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +} diff --git a/src/vdaf/xof.rs b/src/vdaf/xof.rs index 49d2897c..0d05f96e 100644 --- a/src/vdaf/xof.rs +++ b/src/vdaf/xof.rs @@ -27,10 +27,14 @@ use aes::{ }; #[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, @@ -446,6 +450,34 @@ impl RngCore for SeedStreamFixedKeyAes128 { } } +/// XOF based on HMAC-SHA256 and AES128. This XOF is not part of the VDAF spec. +#[derive(Clone, Debug)] +pub struct XofHmacSha256Aes128(Hmac); + +impl Xof<32> for XofHmacSha256Aes128 { + type SeedStream = SeedStreamAes128; + + fn init(seed_bytes: &[u8; 32], dst: &[u8]) -> Self { + let mut mac = 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 update(&mut self, data: &[u8]) { + Mac::update(&mut self.0, data); + } + + 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 { use super::*; @@ -515,6 +547,30 @@ mod tests { test_xof::(); } + #[test] + fn xof_hmac_sha256_aes128() { + let t: XofTestVector = + serde_json::from_str(include_str!("test_vec/XofHmacSha256Aes128.json")).unwrap(); + + let mut xof = XofHmacSha256Aes128::init(&t.seed.try_into().unwrap(), &t.dst); + xof.update(&t.binder); + + assert_eq!( + xof.clone().into_seed(), + Seed(t.derived_seed.try_into().unwrap()) + ); + + let mut bytes = Cursor::new(t.expanded_vec_field128.as_slice()); + let mut want = Vec::with_capacity(t.length); + while (bytes.position() as usize) < t.expanded_vec_field128.len() { + want.push(Field128::decode(&mut bytes).unwrap()) + } + let got: Vec = xof.clone().into_seed_stream().into_field_vec(t.length); + assert_eq!(got, want); + + test_xof::(); + } + #[cfg(feature = "experimental")] #[test] fn xof_fixed_key_aes128() {