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 #[serde(default)]
43 pub aggregation_job_counter_success: i64,
44 #[serde(default)]
45 pub aggregation_job_counter_helper_batch_collected: i64,
46 #[serde(default)]
47 pub aggregation_job_counter_helper_report_replayed: i64,
48 #[serde(default)]
49 pub aggregation_job_counter_helper_report_dropped: i64,
50 #[serde(default)]
51 pub aggregation_job_counter_helper_hpke_unknown_config_id: i64,
52 #[serde(default)]
53 pub aggregation_job_counter_helper_hpke_decrypt_failure: i64,
54 #[serde(default)]
55 pub aggregation_job_counter_helper_vdaf_prep_error: i64,
56 #[serde(default)]
57 pub aggregation_job_counter_helper_task_expired: i64,
58 #[serde(default)]
59 pub aggregation_job_counter_helper_invalid_message: i64,
60 #[serde(default)]
61 pub aggregation_job_counter_helper_report_too_early: i64,
62}
63
64#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
65pub struct NewTask {
66 pub name: String,
67 pub leader_aggregator_id: Uuid,
68 pub helper_aggregator_id: Uuid,
69 pub vdaf: Vdaf,
70 pub min_batch_size: u64,
71 pub max_batch_size: Option<u64>,
72 pub batch_time_window_size_seconds: Option<u64>,
73 pub time_precision_seconds: u64,
74 pub collector_credential_id: Uuid,
75}
76
77#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
78#[serde(rename_all = "snake_case", tag = "type")]
79pub enum Vdaf {
80 #[serde(rename = "count")]
81 Count,
82
83 #[serde(rename = "histogram")]
84 Histogram(Histogram),
85
86 #[serde(rename = "sum")]
87 Sum { bits: u8 },
88
89 #[serde(rename = "count_vec")]
90 CountVec {
91 length: u64,
92 chunk_length: Option<u64>,
93 },
94
95 #[serde(rename = "sum_vec")]
96 SumVec(SumVec),
97}
98
99#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
100#[serde(untagged)]
101pub enum Histogram {
102 Categorical {
103 buckets: Vec<String>,
104 chunk_length: Option<u64>,
105 #[serde(default)]
106 dp_strategy: dp_strategy::Prio3Histogram,
107 },
108 Continuous {
109 buckets: Vec<u64>,
110 chunk_length: Option<u64>,
111 #[serde(default)]
112 dp_strategy: dp_strategy::Prio3Histogram,
113 },
114 Length {
115 length: u64,
116 chunk_length: Option<u64>,
117 #[serde(default)]
118 dp_strategy: dp_strategy::Prio3Histogram,
119 },
120}
121
122impl Histogram {
123 pub fn length(&self) -> usize {
125 match self {
126 Histogram::Categorical { buckets, .. } => buckets.len(),
127 Histogram::Continuous { buckets, .. } => buckets.len() + 1,
128 Histogram::Length { length, .. } => *length as usize,
129 }
130 }
131
132 pub fn chunk_length(&self) -> usize {
134 match self {
135 Histogram::Categorical { chunk_length, .. } => chunk_length,
136 Histogram::Continuous { chunk_length, .. } => chunk_length,
137 Histogram::Length { chunk_length, .. } => chunk_length,
138 }
139 .map(|c| c as usize)
140 .unwrap_or_else(|| optimal_chunk_length(self.length()))
141 }
142
143 pub fn dp_strategy(&self) -> &dp_strategy::Prio3Histogram {
145 match self {
146 Histogram::Categorical { dp_strategy, .. }
147 | Histogram::Continuous { dp_strategy, .. }
148 | Histogram::Length { dp_strategy, .. } => dp_strategy,
149 }
150 }
151}
152
153#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
154pub struct SumVec {
155 pub bits: u8,
156 pub length: u64,
157 chunk_length: Option<u64>,
158 #[serde(default)]
159 pub dp_strategy: dp_strategy::Prio3SumVec,
160}
161
162impl SumVec {
163 pub fn new(
165 bits: u8,
166 length: u64,
167 chunk_length: Option<u64>,
168 dp_strategy: dp_strategy::Prio3SumVec,
169 ) -> Self {
170 Self {
171 bits,
172 length,
173 chunk_length,
174 dp_strategy,
175 }
176 }
177
178 pub fn chunk_length(&self) -> usize {
180 self.chunk_length
181 .map(|c| c as usize)
182 .unwrap_or_else(|| optimal_chunk_length(self.bits as usize * self.length as usize))
183 }
184}