Skip to content

Commit

Permalink
Update XOFs to use TurboSHAKE128 (#851)
Browse files Browse the repository at this point in the history
  • Loading branch information
divergentdave authored Nov 28, 2023
1 parent 0379885 commit acd55f0
Show file tree
Hide file tree
Showing 24 changed files with 431 additions and 397 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ This crate defines the following feature flags:

|Name|Default feature?|Description|
|---|---|---|
|`crypto-dependencies`|Yes|Enables dependencies on various RustCrypto crates, and uses them to implement `XofShake128` to support VDAFs.|
|`crypto-dependencies`|Yes|Enables dependencies on various RustCrypto crates, and uses them to implement `XofTurboShake128` to support VDAFs.|
|`experimental`|No|Certain experimental APIs are guarded by this feature. They may undergo breaking changes in future patch releases, as an exception to semantic versioning.|
|`multithreaded`|No|Enables certain Prio3 VDAF implementations that use `rayon` for parallelization of gadget evaluations.|
|`prio2`|No|Enables the Prio v2 API, and a VDAF based on the Prio2 system.|
4 changes: 2 additions & 2 deletions benches/speed_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ fn poplar1(c: &mut Criterion) {
for size in test_sizes.iter() {
group.throughput(Throughput::Bytes(*size as u64 / 8));
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
let vdaf = Poplar1::new_shake128(size);
let vdaf = Poplar1::new_turboshake128(size);
let mut rng = StdRng::seed_from_u64(RNG_SEED);
let nonce = rng.gen::<[u8; 16]>();

Expand All @@ -736,7 +736,7 @@ fn poplar1(c: &mut Criterion) {
for size in test_sizes.iter() {
group.measurement_time(Duration::from_secs(30)); // slower benchmark
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
let vdaf = Poplar1::new_shake128(size);
let vdaf = Poplar1::new_turboshake128(size);
let mut rng = StdRng::seed_from_u64(RNG_SEED);

b.iter_batched(
Expand Down
22 changes: 11 additions & 11 deletions src/dp/distributions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ mod tests {

use super::*;
use crate::dp::Rational;
use crate::vdaf::xof::SeedStreamSha3;
use crate::vdaf::xof::SeedStreamTurboShake128;

use num_bigint::{BigUint, Sign, ToBigInt, ToBigUint};
use num_traits::{One, Signed, ToPrimitive};
Expand All @@ -306,15 +306,15 @@ mod tests {
DiscreteGaussian::new(Ratio::<BigUint>::from_integer(BigUint::from(5u8))).unwrap();

// check samples are consistent
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap())
.collect();
let samples1: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap())
.collect();
assert_eq!(samples, vec![-3, -11, -3, 5, 1, 5, 2, 2, 1, 18]);
assert_eq!(samples1, vec![4, -4, -5, -2, 0, -5, -3, 1, 1, -2]);
assert_eq!(samples, vec![0, -3, -2, 3, 2, -1, -5, 4, -7, -5]);
assert_eq!(samples1, vec![2, 7, -8, -3, 1, -3, -3, 6, -3, -1]);
}

#[test]
Expand All @@ -325,7 +325,7 @@ mod tests {
// sample from a manually created distribution
let sampler1 =
DiscreteGaussian::new(Ratio::<BigUint>::from_integer(BigUint::from(4u8))).unwrap();
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples1: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler1.sample(&mut rng)).unwrap())
.collect();
Expand All @@ -337,7 +337,7 @@ mod tests {
let sampler2 = zcdp
.create_distribution(Ratio::<BigUint>::from_integer(1u8.into()))
.unwrap();
let mut rng2 = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng2 = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples2: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler2.sample(&mut rng2)).unwrap())
.collect();
Expand Down Expand Up @@ -485,7 +485,7 @@ mod tests {
.unwrap();

// collect that number of samples
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples: Vec<BigInt> = (1..n_samples)
.map(|_| {
sample_discrete_gaussian(&Ratio::<BigUint>::from_integer(sigma.clone()), &mut rng)
Expand Down Expand Up @@ -519,7 +519,7 @@ mod tests {
#[test]
fn empirical_test_gauss() {
[100, 2000, 20000].iter().for_each(|p| {
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_discrete_gaussian(
&Ratio::<BigUint>::from_integer((*p).to_biguint().unwrap()),
Expand All @@ -541,7 +541,7 @@ mod tests {
#[test]
fn empirical_test_bernoulli_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
if sample_bernoulli(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
Expand All @@ -565,7 +565,7 @@ mod tests {
#[test]
fn empirical_test_geometric_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_geometric_exp(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
Expand All @@ -588,7 +588,7 @@ mod tests {
#[test]
fn empirical_test_laplace_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_discrete_laplace(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
Expand Down
4 changes: 2 additions & 2 deletions src/flp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0

//! Implementation of the generic Fully Linear Proof (FLP) system specified in
//! [[draft-irtf-cfrg-vdaf-07]]. This is the main building block of [`Prio3`](crate::vdaf::prio3).
//! [[draft-irtf-cfrg-vdaf-08]]. This is the main building block of [`Prio3`](crate::vdaf::prio3).
//!
//! The FLP is derived for any implementation of the [`Type`] trait. Such an implementation
//! specifies a validity circuit that defines the set of valid measurements, as well as the finite
Expand Down Expand Up @@ -44,7 +44,7 @@
//! assert!(count.decide(&verifier).unwrap());
//! ```
//!
//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
#[cfg(feature = "experimental")]
use crate::dp::DifferentialPrivacyStrategy;
Expand Down
28 changes: 20 additions & 8 deletions src/flp/types/fixedpoint_l2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ use crate::flp::gadgets::{Mul, ParallelSumGadget, PolyEval};
use crate::flp::types::fixedpoint_l2::compatible_float::CompatibleFloat;
use crate::flp::types::parallel_sum_range_checks;
use crate::flp::{FlpError, Gadget, Type, TypeWithNoise};
use crate::vdaf::xof::SeedStreamSha3;
use crate::vdaf::xof::SeedStreamTurboShake128;
use fixed::traits::Fixed;
use num_bigint::{BigInt, BigUint, TryFromBigIntError};
use num_integer::Integer;
Expand Down Expand Up @@ -638,7 +638,11 @@ where
agg_result: &mut [Self::Field],
_num_measurements: usize,
) -> Result<(), FlpError> {
self.add_noise(dp_strategy, agg_result, &mut SeedStreamSha3::from_entropy())
self.add_noise(
dp_strategy,
agg_result,
&mut SeedStreamTurboShake128::from_entropy(),
)
}
}

Expand Down Expand Up @@ -681,7 +685,7 @@ mod tests {
use crate::field::{random_vector, Field128, FieldElement};
use crate::flp::gadgets::ParallelSum;
use crate::flp::types::test_utils::{flp_validity_test, ValidityTestCase};
use crate::vdaf::xof::SeedStreamSha3;
use crate::vdaf::xof::SeedStreamTurboShake128;
use fixed::types::extra::{U127, U14, U63};
use fixed::{FixedI128, FixedI16, FixedI64};
use fixed_macro::fixed;
Expand Down Expand Up @@ -762,15 +766,23 @@ mod tests {
let strategy = ZCdpDiscreteGaussian::from_budget(ZCdpBudget::new(
Rational::from_unsigned(100u8, 3u8).unwrap(),
));
vsum.add_noise(&strategy, &mut v, &mut SeedStreamSha3::from_seed([0u8; 16]))
.unwrap();
vsum.add_noise(
&strategy,
&mut v,
&mut SeedStreamTurboShake128::from_seed([0u8; 16]),
)
.unwrap();
assert_eq!(
vsum.decode_result(&v, 1).unwrap(),
match n {
// sensitivity depends on encoding so the noise differs
16 => vec![0.150604248046875, 0.139373779296875, -0.03759765625],
32 => vec![0.3051439793780446, 0.1226568529382348, 0.08595499861985445],
64 => vec![0.2896077990915178, 0.16115188007715098, 0.0788390114728425],
16 => vec![0.288970947265625, 0.168853759765625, 0.085662841796875],
32 => vec![0.257810294162482, 0.10634658299386501, 0.10149003705009818],
64 => vec![
0.37697368351762867,
-0.02388947667663828,
0.19813152630930916
],
_ => panic!("unsupported bitsize"),
}
);
Expand Down
5 changes: 3 additions & 2 deletions src/idpf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module implements the incremental distributed point function (IDPF) described in
//! [[draft-irtf-cfrg-vdaf-07]].
//! [[draft-irtf-cfrg-vdaf-08]].
//!
//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
use crate::{
codec::{CodecError, Decode, Encode, ParameterizedDecode},
Expand Down Expand Up @@ -1901,6 +1901,7 @@ mod tests {
}

#[test]
#[ignore = "VDAF-08 support is incomplete"]
fn idpf_poplar_generate_test_vector() {
let test_vector = load_idpfpoplar_test_vector();
let idpf = Idpf::new((), ());
Expand Down
28 changes: 14 additions & 14 deletions src/prng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ mod tests {
use crate::{
codec::Decode,
field::{Field64, FieldPrio2},
vdaf::xof::{Seed, SeedStreamSha3, Xof, XofShake128},
vdaf::xof::{Seed, SeedStreamTurboShake128, Xof, XofTurboShake128},
};
#[cfg(feature = "prio2")]
use base64::{engine::Engine, prelude::BASE64_STANDARD};
Expand Down Expand Up @@ -219,22 +219,22 @@ mod tests {
// These constants were found in a brute-force search, and they test that the XOF performs
// rejection sampling correctly when the raw output exceeds the prime modulus.
let seed = Seed::get_decoded(&[
0x29, 0xb2, 0x98, 0x64, 0xb4, 0xaa, 0x4e, 0x07, 0x2a, 0x44, 0x49, 0x24, 0xf6, 0x74,
0x0a, 0x3d,
0xd5, 0x3f, 0xff, 0x5d, 0x88, 0x8c, 0x60, 0x4e, 0x9f, 0x24, 0x16, 0xe1, 0xa2, 0x0a,
0x62, 0x34,
])
.unwrap();
let expected = Field64::from(2035552711764301796);
let expected = Field64::from(3401316594827516850);

let seed_stream = XofShake128::seed_stream(&seed, b"", b"");
let seed_stream = XofTurboShake128::seed_stream(&seed, b"", b"");
let mut prng = Prng::<Field64, _>::from_seed_stream(seed_stream);
let actual = prng.nth(33236).unwrap();
let actual = prng.nth(662).unwrap();
assert_eq!(actual, expected);

#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
{
let mut seed_stream = XofShake128::seed_stream(&seed, b"", b"");
let mut seed_stream = XofTurboShake128::seed_stream(&seed, b"", b"");
let mut actual = <Field64 as FieldElement>::zero();
for _ in 0..=33236 {
for _ in 0..=662 {
actual = <Field64 as crate::idpf::IdpfValue>::generate(&mut seed_stream, &());
}
assert_eq!(actual, expected);
Expand All @@ -247,12 +247,12 @@ mod tests {
fn left_over_buffer_back_fill() {
let seed = Seed::generate().unwrap();

let mut prng: Prng<Field64, SeedStreamSha3> =
Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
let mut prng: Prng<Field64, SeedStreamTurboShake128> =
Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));

// Construct a `Prng` with a longer-than-usual buffer.
let mut prng_weird_buffer_size: Prng<Field64, SeedStreamSha3> =
Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
let mut prng_weird_buffer_size: Prng<Field64, SeedStreamTurboShake128> =
Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));
let mut extra = [0; 7];
prng_weird_buffer_size.seed_stream.fill_bytes(&mut extra);
prng_weird_buffer_size.buffer.extend_from_slice(&extra);
Expand All @@ -268,8 +268,8 @@ mod tests {
#[test]
fn into_new_field() {
let seed = Seed::generate().unwrap();
let want: Prng<Field64, SeedStreamSha3> =
Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
let want: Prng<Field64, SeedStreamTurboShake128> =
Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));
let want_buffer = want.buffer.clone();

let got: Prng<FieldPrio2, _> = want.into_new_field();
Expand Down
20 changes: 11 additions & 9 deletions src/topology/ping_pong.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! two aggregators, designated "Leader" and "Helper". This topology is required for implementing
//! the [Distributed Aggregation Protocol][DAP].
//!
//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
//! [DAP]: https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap
use crate::{
Expand Down Expand Up @@ -64,7 +64,7 @@ pub enum PingPongError {
/// variants are opaque byte buffers. This is because the ping-pong routines take responsibility for
/// decoding preparation shares and messages, which usually requires having the preparation state.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, PartialEq, Eq)]
pub enum PingPongMessage {
/// Corresponds to MessageType.initialize.
Expand Down Expand Up @@ -183,7 +183,7 @@ impl Decode for PingPongMessage {
/// preprocessed prepare message. Their encoding is much smaller than the `(State, Message)` tuple,
/// which can always be recomputed with [`Self::evaluate`].
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, Debug, Eq)]
pub struct PingPongTransition<
const VERIFY_KEY_SIZE: usize,
Expand Down Expand Up @@ -294,7 +294,7 @@ where
/// code, and the `Rejected` state is represented as `std::result::Result::Err`, so this enum does
/// not include those variants.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PingPongState<
const VERIFY_KEY_SIZE: usize,
Expand Down Expand Up @@ -332,7 +332,7 @@ pub enum PingPongContinuedValue<

/// Extension trait on [`crate::vdaf::Aggregator`] which adds the [VDAF Ping-Pong Topology][VDAF].
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>:
Aggregator<VERIFY_KEY_SIZE, NONCE_SIZE>
{
Expand All @@ -352,7 +352,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
/// leader along with the next [`PingPongMessage`] received from the helper as input to
/// [`Self::leader_continued`] to advance to the next round.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn leader_initialized(
&self,
verify_key: &[u8; VERIFY_KEY_SIZE],
Expand All @@ -363,7 +363,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
) -> Result<(Self::State, PingPongMessage), PingPongError>;

/// Initialize helper state using the helper's input share and the leader's first prepare share.
/// Corresponds to `ping_pong_helper_init` in the forthcoming `draft-irtf-cfrg-vdaf-07`.
/// Corresponds to `ping_pong_helper_init` in [VDAF].
///
/// If successful, the returned [`PingPongTransition`] should be evaluated, yielding a
/// [`PingPongMessage`], which should be transmitted to the leader, and a [`PingPongState`].
Expand All @@ -379,6 +379,8 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
/// # Errors
///
/// `inbound` must be `PingPongMessage::Initialize` or the function will fail.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn helper_initialized(
&self,
verify_key: &[u8; VERIFY_KEY_SIZE],
Expand Down Expand Up @@ -416,7 +418,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
///
/// `inbound` must not be `PingPongMessage::Initialize` or the function will fail.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn leader_continued(
&self,
leader_state: Self::State,
Expand Down Expand Up @@ -451,7 +453,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
///
/// `inbound` must not be `PingPongMessage::Initialize` or the function will fail.
///
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn helper_continued(
&self,
helper_state: Self::State,
Expand Down
Loading

0 comments on commit acd55f0

Please sign in to comment.