divviup_client/
task.rs

1use prio::vdaf::prio3::optimal_chunk_length;
2use serde::{Deserialize, Serialize};
3use time::OffsetDateTime;
4use uuid::Uuid;
5
6use crate::dp_strategy;
7
8#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
9pub struct Task {
10    pub id: String,
11    pub account_id: Uuid,
12    pub name: String,
13    pub vdaf: Vdaf,
14    pub min_batch_size: u64,
15    pub max_batch_size: Option<u64>,
16    pub batch_time_window_size_seconds: Option<u64>,
17    #[serde(with = "time::serde::rfc3339")]
18    pub created_at: OffsetDateTime,
19    #[serde(with = "time::serde::rfc3339")]
20    pub updated_at: OffsetDateTime,
21    #[serde(with = "time::serde::rfc3339::option")]
22    pub deleted_at: Option<OffsetDateTime>,
23    pub time_precision_seconds: u32,
24    #[deprecated = "Not populated. Will be removed in a future release."]
25    pub report_count: u32,
26    #[deprecated = "Not populated. Will be removed in a future release."]
27    pub aggregate_collection_count: u32,
28    #[serde(default, with = "time::serde::rfc3339::option")]
29    pub expiration: Option<OffsetDateTime>,
30    pub leader_aggregator_id: Uuid,
31    pub helper_aggregator_id: Uuid,
32    pub collector_credential_id: Uuid,
33    pub report_counter_interval_collected: i64,
34    pub report_counter_decode_failure: i64,
35    pub report_counter_decrypt_failure: i64,
36    pub report_counter_expired: i64,
37    pub report_counter_outdated_key: i64,
38    pub report_counter_success: i64,
39    pub report_counter_too_early: i64,
40    pub report_counter_task_expired: i64,
41}
42
43#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
44pub struct NewTask {
45    pub name: String,
46    pub leader_aggregator_id: Uuid,
47    pub helper_aggregator_id: Uuid,
48    pub vdaf: Vdaf,
49    pub min_batch_size: u64,
50    pub max_batch_size: Option<u64>,
51    pub batch_time_window_size_seconds: Option<u64>,
52    pub time_precision_seconds: u64,
53    pub collector_credential_id: Uuid,
54}
55
56#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
57#[serde(rename_all = "snake_case", tag = "type")]
58pub enum Vdaf {
59    #[serde(rename = "count")]
60    Count,
61
62    #[serde(rename = "histogram")]
63    Histogram(Histogram),
64
65    #[serde(rename = "sum")]
66    Sum { bits: u8 },
67
68    #[serde(rename = "count_vec")]
69    CountVec {
70        length: u64,
71        chunk_length: Option<u64>,
72    },
73
74    #[serde(rename = "sum_vec")]
75    SumVec(SumVec),
76}
77
78#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
79#[serde(untagged)]
80pub enum Histogram {
81    Categorical {
82        buckets: Vec<String>,
83        chunk_length: Option<u64>,
84        #[serde(default)]
85        dp_strategy: dp_strategy::Prio3Histogram,
86    },
87    Continuous {
88        buckets: Vec<u64>,
89        chunk_length: Option<u64>,
90        #[serde(default)]
91        dp_strategy: dp_strategy::Prio3Histogram,
92    },
93    Length {
94        length: u64,
95        chunk_length: Option<u64>,
96        #[serde(default)]
97        dp_strategy: dp_strategy::Prio3Histogram,
98    },
99}
100
101impl Histogram {
102    /// The length of this histogram, i.e. the number of buckets.
103    pub fn length(&self) -> usize {
104        match self {
105            Histogram::Categorical { buckets, .. } => buckets.len(),
106            Histogram::Continuous { buckets, .. } => buckets.len() + 1,
107            Histogram::Length { length, .. } => *length as usize,
108        }
109    }
110
111    /// The chunk length used in the VDAF.
112    pub fn chunk_length(&self) -> usize {
113        match self {
114            Histogram::Categorical { chunk_length, .. } => chunk_length,
115            Histogram::Continuous { chunk_length, .. } => chunk_length,
116            Histogram::Length { chunk_length, .. } => chunk_length,
117        }
118        .map(|c| c as usize)
119        .unwrap_or_else(|| optimal_chunk_length(self.length()))
120    }
121
122    /// The differential privacy strategy.
123    pub fn dp_strategy(&self) -> &dp_strategy::Prio3Histogram {
124        match self {
125            Histogram::Categorical { dp_strategy, .. }
126            | Histogram::Continuous { dp_strategy, .. }
127            | Histogram::Length { dp_strategy, .. } => dp_strategy,
128        }
129    }
130}
131
132#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
133pub struct SumVec {
134    pub bits: u8,
135    pub length: u64,
136    chunk_length: Option<u64>,
137    #[serde(default)]
138    pub dp_strategy: dp_strategy::Prio3SumVec,
139}
140
141impl SumVec {
142    /// Create a new SumVec
143    pub fn new(
144        bits: u8,
145        length: u64,
146        chunk_length: Option<u64>,
147        dp_strategy: dp_strategy::Prio3SumVec,
148    ) -> Self {
149        Self {
150            bits,
151            length,
152            chunk_length,
153            dp_strategy,
154        }
155    }
156
157    /// The chunk length used in the VDAF.
158    pub fn chunk_length(&self) -> usize {
159        self.chunk_length
160            .map(|c| c as usize)
161            .unwrap_or_else(|| optimal_chunk_length(self.bits as usize * self.length as usize))
162    }
163}