Skip to content

Commit

Permalink
taskprov: Enable Prio3SumVecField64MultiproofHmacSha256Aes128 in draft09
Browse files Browse the repository at this point in the history
Enable the Prio3SumVec variant in taskprov. Don't enable it in draft02,
since the version of Prio3 we need (draft-irtf-cfrg-vdaf-08) is
incompatible with draft02.

While at it, unify the encoding logic across draft02 and draft09 so that
the same method is called to encode the query, VDAF, and DP parameters.
(The length prefix is only added in draft09.)
  • Loading branch information
cjpatton committed Dec 4, 2023
1 parent b107a07 commit f72c93a
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 66 deletions.
2 changes: 1 addition & 1 deletion daphne/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl DapTaskParameters {
task_expiration: now + 86400 * 14, // expires in two weeks
vdaf_config: messages::taskprov::VdafConfig {
dp_config: messages::taskprov::DpConfig::None,
var: messages::taskprov::VdafTypeVar::Prio2 { dimension: 10 },
var: (&self.vdaf).try_into()?,
},
};

Expand Down
25 changes: 0 additions & 25 deletions daphne/src/messages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,31 +1288,6 @@ fn decode_u16_prefixed<O>(
Ok(decoded)
}

fn encode_u16_item_for_version<E: ParameterizedEncode<DapVersion>>(
bytes: &mut Vec<u8>,
version: DapVersion,
item: &E,
) {
match version {
DapVersion::DraftLatest => encode_u16_prefixed(version, bytes, |version, bytes| {
item.encode_with_param(&version, bytes);
}),
DapVersion::Draft02 => item.encode_with_param(&version, bytes),
}
}

fn decode_u16_item_for_version<D: ParameterizedDecode<DapVersion>>(
version: DapVersion,
bytes: &mut Cursor<&[u8]>,
) -> Result<D, CodecError> {
match version {
DapVersion::DraftLatest => decode_u16_prefixed(version, bytes, |version, inner| {
D::decode_with_param(&version, inner)
}),
DapVersion::Draft02 => D::decode_with_param(&version, bytes),
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
159 changes: 129 additions & 30 deletions daphne/src/messages/taskprov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//! draft-wang-ppm-dap-taskprov: Messages for the taskrpov extension for DAP.
use crate::messages::{
decode_u16_bytes, decode_u16_item_for_version, encode_u16_bytes, encode_u16_item_for_version,
Duration, Time, QUERY_TYPE_FIXED_SIZE, QUERY_TYPE_TIME_INTERVAL,
decode_u16_bytes, encode_u16_bytes, Duration, Time, QUERY_TYPE_FIXED_SIZE,
QUERY_TYPE_TIME_INTERVAL,
};
use crate::DapVersion;
use prio::codec::{
Expand All @@ -15,32 +15,61 @@ use prio::codec::{
use serde::{Deserialize, Serialize};
use std::io::Cursor;

use super::{decode_u16_prefixed, encode_u16_prefixed};

// VDAF type codes.
const VDAF_TYPE_PRIO2: u32 = 0xFFFF_0000;
pub(crate) const VDAF_TYPE_PRIO3_SUM_VEC_FIELD64_MULTIPROOF_HMAC_SHA256_AES128: u32 = 0xFFFF_1003;

// Differential privacy mechanism types.
const DP_MECHANISM_NONE: u8 = 0x01;

/// A VDAF type along with its type-specific data.
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)]
pub enum VdafTypeVar {
Prio2 { dimension: u32 },
NotImplemented { typ: u32, param: Vec<u8> },
Prio2 {
dimension: u32,
},
Prio3SumVecField64MultiproofHmacSha256Aes128 {
bits: u8,
length: u32,
chunk_length: u32,
num_proofs: u8,
},
NotImplemented {
typ: u32,
param: Vec<u8>,
},
}

impl ParameterizedEncode<DapVersion> for VdafTypeVar {
fn encode_with_param(&self, version: &DapVersion, bytes: &mut Vec<u8>) {
match self {
Self::Prio2 { dimension } => {
VDAF_TYPE_PRIO2.encode(bytes);
encode_u16_item_for_version(bytes, *version, dimension);
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
dimension.encode(inner);
});
}
Self::Prio3SumVecField64MultiproofHmacSha256Aes128 {
bits,
length,
chunk_length,
num_proofs,
} => {
VDAF_TYPE_PRIO3_SUM_VEC_FIELD64_MULTIPROOF_HMAC_SHA256_AES128.encode(bytes);
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
bits.encode(inner);
length.encode(inner);
chunk_length.encode(inner);
num_proofs.encode(inner);
});
}
Self::NotImplemented { typ, param } => {
typ.encode(bytes);
match version {
DapVersion::DraftLatest => encode_u16_bytes(bytes, param),
DapVersion::Draft02 => bytes.extend_from_slice(param),
}
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
inner.extend_from_slice(param);
});
}
}
}
Expand All @@ -53,9 +82,23 @@ impl ParameterizedDecode<DapVersion> for VdafTypeVar {
) -> Result<Self, CodecError> {
let vdaf_type = u32::decode(bytes)?;
match (version, vdaf_type) {
(.., VDAF_TYPE_PRIO2) => Ok(Self::Prio2 {
dimension: decode_u16_item_for_version(*version, bytes)?,
}),
(.., VDAF_TYPE_PRIO2) => {
taskprov_decode_u16_prefixed(*version, bytes, |_version, inner| {
Ok(Self::Prio2 {
dimension: u32::decode(inner)?,
})
})
}
(.., VDAF_TYPE_PRIO3_SUM_VEC_FIELD64_MULTIPROOF_HMAC_SHA256_AES128) => {
taskprov_decode_u16_prefixed(*version, bytes, |_version, inner| {
Ok(Self::Prio3SumVecField64MultiproofHmacSha256Aes128 {
bits: u8::decode(inner)?,
length: u32::decode(inner)?,
chunk_length: u32::decode(inner)?,
num_proofs: u8::decode(inner)?,
})
})
}
(DapVersion::DraftLatest, ..) => Ok(Self::NotImplemented {
typ: vdaf_type,
param: decode_u16_bytes(bytes)?,
Expand All @@ -79,15 +122,14 @@ impl ParameterizedEncode<DapVersion> for DpConfig {
match self {
Self::None => {
DP_MECHANISM_NONE.encode(bytes);
encode_u16_item_for_version(bytes, *version, &());
taskprov_encode_u16_prefixed(*version, bytes, |_, _| ());
}

Self::NotImplemented { typ, param } => {
typ.encode(bytes);
match version {
DapVersion::DraftLatest => encode_u16_bytes(bytes, param),
DapVersion::Draft02 => bytes.extend_from_slice(param),
}
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
inner.extend_from_slice(param);
});
}
}
}
Expand All @@ -101,7 +143,9 @@ impl ParameterizedDecode<DapVersion> for DpConfig {
let dp_mechanism = u8::decode(bytes)?;
match (version, dp_mechanism) {
(.., DP_MECHANISM_NONE) => {
decode_u16_item_for_version::<()>(*version, bytes)?;
taskprov_decode_u16_prefixed::<()>(*version, bytes, |_version, inner| {
<()>::decode(inner)
})?;
Ok(Self::None)
}
(DapVersion::DraftLatest, ..) => Ok(Self::NotImplemented {
Expand Down Expand Up @@ -207,18 +251,19 @@ impl ParameterizedEncode<DapVersion> for QueryConfig {
match &self.var {
QueryConfigVar::TimeInterval => {
QUERY_TYPE_TIME_INTERVAL.encode(bytes);
encode_u16_item_for_version(bytes, *version, &());
taskprov_encode_u16_prefixed(*version, bytes, |_, _| ());
}
QueryConfigVar::FixedSize { max_batch_size } => {
QUERY_TYPE_FIXED_SIZE.encode(bytes);
encode_u16_item_for_version(bytes, *version, max_batch_size);
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
max_batch_size.encode(inner);
});
}
QueryConfigVar::NotImplemented { typ, param } => {
typ.encode(bytes);
match version {
DapVersion::DraftLatest => encode_u16_bytes(bytes, param),
DapVersion::Draft02 => bytes.extend_from_slice(param),
}
taskprov_encode_u16_prefixed(*version, bytes, |_version, inner| {
inner.extend_from_slice(param);
});
}
}
}
Expand All @@ -239,12 +284,18 @@ impl ParameterizedDecode<DapVersion> for QueryConfig {
let query_type = query_type.unwrap_or(u8::decode(bytes)?);
let var = match (version, query_type) {
(.., QUERY_TYPE_TIME_INTERVAL) => {
decode_u16_item_for_version::<()>(*version, bytes)?;
taskprov_decode_u16_prefixed::<()>(*version, bytes, |_version, inner| {
<()>::decode(inner)
})?;
QueryConfigVar::TimeInterval
}
(.., QUERY_TYPE_FIXED_SIZE) => QueryConfigVar::FixedSize {
max_batch_size: decode_u16_item_for_version(*version, bytes)?,
},
(.., QUERY_TYPE_FIXED_SIZE) => {
taskprov_decode_u16_prefixed(*version, bytes, |_version, inner| {
Ok(QueryConfigVar::FixedSize {
max_batch_size: u32::decode(inner)?,
})
})?
}
(DapVersion::DraftLatest, ..) => QueryConfigVar::NotImplemented {
typ: query_type,
param: decode_u16_bytes(bytes)?,
Expand Down Expand Up @@ -318,6 +369,30 @@ impl ParameterizedDecode<DapVersion> for TaskConfig {
}
}

fn taskprov_encode_u16_prefixed(
version: DapVersion,
bytes: &mut Vec<u8>,
e: impl Fn(DapVersion, &mut Vec<u8>),
) {
match version {
DapVersion::DraftLatest => encode_u16_prefixed(version, bytes, e),
// draft02 compatibility: No length prefix is used.
DapVersion::Draft02 => e(version, bytes),
}
}

fn taskprov_decode_u16_prefixed<O>(
version: DapVersion,
bytes: &mut Cursor<&[u8]>,
d: impl Fn(DapVersion, &mut Cursor<&[u8]>) -> Result<O, CodecError>,
) -> Result<O, CodecError> {
match version {
DapVersion::DraftLatest => decode_u16_prefixed(version, bytes, d),
// draft02 compatibility: No length prefix is used.
DapVersion::Draft02 => d(version, bytes),
}
}

#[cfg(test)]
mod tests {
use crate::test_versions;
Expand Down Expand Up @@ -443,7 +518,7 @@ mod tests {
.is_err());
}

fn roundtrip_vdaf_config(version: DapVersion) {
fn roundtrip_vdaf_config_prio2(version: DapVersion) {
let vdaf_config = VdafConfig {
dp_config: DpConfig::None,
var: VdafTypeVar::Prio2 { dimension: 1337 },
Expand All @@ -458,7 +533,31 @@ mod tests {
);
}

test_versions! { roundtrip_vdaf_config }
test_versions! { roundtrip_vdaf_config_prio2 }

fn roundtrip_vdaf_config_prio3_sum_vec_field64_multiproof_hmac_sha256_aes128(
version: DapVersion,
) {
let vdaf_config = VdafConfig {
dp_config: DpConfig::None,
var: VdafTypeVar::Prio3SumVecField64MultiproofHmacSha256Aes128 {
bits: 23,
length: 1337,
chunk_length: 42,
num_proofs: 99,
},
};
assert_eq!(
VdafConfig::get_decoded_with_param(
&version,
&vdaf_config.get_encoded_with_param(&version)
)
.unwrap(),
vdaf_config
);
}

test_versions! { roundtrip_vdaf_config_prio3_sum_vec_field64_multiproof_hmac_sha256_aes128 }

#[test]
fn roundtrip_vdaf_config_not_implemented_draft09() {
Expand Down
35 changes: 32 additions & 3 deletions daphne/src/roles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1795,14 +1795,19 @@ mod test {

async_test_versions! { e2e_fixed_size }

async fn e2e_taskprov(version: DapVersion) {
async fn e2e_taskprov(
version: DapVersion,
vdaf_config: VdafConfig,
test_measurement: DapMeasurement,
) {
let t = Test::new(version);

let (task_config, task_id, taskprov_advertisement, taskprov_report_extension_payload) =
DapTaskParameters {
version,
min_batch_size: 1,
query: DapQueryConfig::FixedSize { max_batch_size: 2 },
vdaf: vdaf_config,
..Default::default()
}
.to_config_with_taskprov(
Expand Down Expand Up @@ -1835,7 +1840,7 @@ mod test {
&hpke_config_list,
t.now,
&task_id,
DapMeasurement::U32Vec(vec![1; 10]),
test_measurement.clone(),
vec![Extension::Taskprov {
draft02_payload: match version {
DapVersion::DraftLatest => None,
Expand Down Expand Up @@ -1893,7 +1898,31 @@ mod test {
});
}

async_test_versions! { e2e_taskprov }
async fn e2e_taskprov_prio2(version: DapVersion) {
e2e_taskprov(
version,
VdafConfig::Prio2 { dimension: 10 },
DapMeasurement::U32Vec(vec![1; 10]),
)
.await;
}

async_test_versions! { e2e_taskprov_prio2 }

#[tokio::test]
async fn e2e_taskprov_prio3_sum_vec_field64_multiproof_hmac_sha256_aes128_draft09() {
e2e_taskprov(
DapVersion::DraftLatest,
VdafConfig::Prio3(Prio3Config::SumVecField64MultiproofHmacSha256Aes128 {
bits: 1,
length: 10,
chunk_length: 2,
num_proofs: 4,
}),
DapMeasurement::U64Vec(vec![1; 10]),
)
.await;
}

fn early_metadata_checks(version: DapVersion) {
let t = Test::new(version);
Expand Down
Loading

0 comments on commit f72c93a

Please sign in to comment.