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 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 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 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 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 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}