1use hybrid_array::Array;
9use hybrid_array::typenum::{Sum, Unsigned};
10
11use crate::{
12 BlindedElement, CipherSuite, Error, EvaluationElement, Group, OprfClient, OprfServer,
13 PoprfClient, PoprfServer, Proof, Result, VoprfClient, VoprfServer,
14};
15
16fn deserialize_elem<G: Group>(input: &mut &[u8]) -> Result<G::Elem> {
22 let input = input
23 .take_ext(G::ElemLen::USIZE)
24 .ok_or(Error::Deserialization)?;
25 G::deserialize_elem(input)
26}
27
28fn deserialize_scalar<G: Group>(input: &mut &[u8]) -> Result<G::Scalar> {
29 let input = input
30 .take_ext(G::ScalarLen::USIZE)
31 .ok_or(Error::Deserialization)?;
32 G::deserialize_scalar(input)
33}
34
35trait SliceExt {
36 fn take_ext<'a>(self: &mut &'a Self, take: usize) -> Option<&'a Self>;
37}
38
39impl<T> SliceExt for [T] {
40 fn take_ext<'a>(self: &mut &'a Self, take: usize) -> Option<&'a Self> {
41 if take > self.len() {
42 return None;
43 }
44
45 let (front, back) = self.split_at(take);
46 *self = back;
47 Some(front)
48 }
49}
50
51macro_rules! impl_serde_scalar {
57 ($ty:ident, $len:ident, $field:ident) => {
58 pub type $len<CS> = <<CS as CipherSuite>::Group as Group>::ScalarLen;
60
61 impl<CS: CipherSuite> $ty<CS> {
62 pub fn serialize(&self) -> Array<u8, $len<CS>> {
64 CS::Group::serialize_scalar(self.$field)
65 }
66
67 pub fn deserialize(mut input: &[u8]) -> Result<Self> {
72 let $field = deserialize_scalar::<CS::Group>(&mut input)?;
73
74 if !input.is_empty() {
75 return Err(Error::Deserialization);
76 }
77
78 Ok(Self { $field })
79 }
80 }
81 };
82}
83
84macro_rules! impl_serde_scalar_elem {
85 ($ty:ident, $len:ident, $scalar_field:ident, $elem_field:ident) => {
86 pub type $len<CS> = Sum<
88 <<CS as CipherSuite>::Group as Group>::ScalarLen,
89 <<CS as CipherSuite>::Group as Group>::ElemLen,
90 >;
91
92 impl<CS: CipherSuite> $ty<CS> {
93 pub fn serialize(&self) -> Array<u8, $len<CS>> {
95 <CS::Group as Group>::serialize_scalar(self.$scalar_field)
96 .concat(<CS::Group as Group>::serialize_elem(self.$elem_field))
97 }
98
99 pub fn deserialize(mut input: &[u8]) -> Result<Self> {
104 let $scalar_field = deserialize_scalar::<CS::Group>(&mut input)?;
105 let $elem_field = deserialize_elem::<CS::Group>(&mut input)?;
106
107 if !input.is_empty() {
108 return Err(Error::Deserialization);
109 }
110
111 Ok(Self {
112 $scalar_field,
113 $elem_field,
114 })
115 }
116 }
117 };
118}
119
120macro_rules! impl_serde_elem {
121 ($ty:ident, $len:ident) => {
122 pub type $len<CS> = <<CS as CipherSuite>::Group as Group>::ElemLen;
124
125 impl<CS: CipherSuite> $ty<CS> {
126 pub fn serialize(&self) -> Array<u8, $len<CS>> {
128 CS::Group::serialize_elem(self.0)
129 }
130
131 pub fn deserialize(mut input: &[u8]) -> Result<Self> {
136 let value = deserialize_elem::<CS::Group>(&mut input)?;
137
138 if !input.is_empty() {
139 return Err(Error::Deserialization);
140 }
141
142 Ok(Self(value))
143 }
144 }
145 };
146}
147
148impl_serde_scalar!(OprfClient, OprfClientLen, blind);
154impl_serde_scalar!(OprfServer, OprfServerLen, sk);
155
156impl_serde_elem!(BlindedElement, BlindedElementLen);
157impl_serde_elem!(EvaluationElement, EvaluationElementLen);
158
159impl_serde_scalar_elem!(VoprfClient, VoprfClientLen, blind, blinded_element);
160impl_serde_scalar_elem!(PoprfClient, PoprfClientLen, blind, blinded_element);
161impl_serde_scalar_elem!(VoprfServer, VoprfServerLen, sk, pk);
162impl_serde_scalar_elem!(PoprfServer, PoprfServerLen, sk, pk);
163
164pub type ProofLen<CS> = Sum<
171 <<CS as CipherSuite>::Group as Group>::ScalarLen,
172 <<CS as CipherSuite>::Group as Group>::ScalarLen,
173>;
174
175impl<CS: CipherSuite> Proof<CS> {
176 pub fn serialize(&self) -> Array<u8, ProofLen<CS>> {
178 CS::Group::serialize_scalar(self.c_scalar)
179 .concat(CS::Group::serialize_scalar(self.s_scalar))
180 }
181
182 pub fn deserialize(mut input: &[u8]) -> Result<Self> {
187 let c_scalar = deserialize_scalar::<CS::Group>(&mut input)?;
188 let s_scalar = deserialize_scalar::<CS::Group>(&mut input)?;
189
190 if !input.is_empty() {
191 return Err(Error::Deserialization);
192 }
193
194 Ok(Proof { c_scalar, s_scalar })
195 }
196}
197
198#[cfg(feature = "serde")]
204pub(crate) mod serde {
205 use core::marker::PhantomData;
206
207 use hybrid_array::Array;
208 use serde::de::{Deserializer, Error};
209 use serde::ser::Serializer;
210 use serde::{Deserialize, Serialize};
211
212 use crate::Group;
213
214 pub(crate) struct Element<G: Group>(PhantomData<G>);
215
216 impl<'de, G: Group> Element<G> {
217 pub(crate) fn deserialize<D>(deserializer: D) -> Result<G::Elem, D::Error>
218 where
219 D: Deserializer<'de>,
220 {
221 Array::<_, G::ElemLen>::deserialize(deserializer)
222 .and_then(|bytes| G::deserialize_elem(&bytes).map_err(D::Error::custom))
223 }
224
225 pub(crate) fn serialize<S>(self_: &G::Elem, serializer: S) -> Result<S::Ok, S::Error>
226 where
227 S: Serializer,
228 {
229 G::serialize_elem(*self_).serialize(serializer)
230 }
231 }
232
233 pub(crate) struct Scalar<G: Group>(PhantomData<G>);
234
235 impl<'de, G: Group> Scalar<G> {
236 pub(crate) fn deserialize<D>(deserializer: D) -> Result<G::Scalar, D::Error>
237 where
238 D: Deserializer<'de>,
239 {
240 Array::<_, G::ScalarLen>::deserialize(deserializer)
241 .and_then(|bytes| G::deserialize_scalar(&bytes).map_err(D::Error::custom))
242 }
243
244 pub(crate) fn serialize<S>(self_: &G::Scalar, serializer: S) -> Result<S::Ok, S::Error>
245 where
246 S: Serializer,
247 {
248 G::serialize_scalar(*self_).serialize(serializer)
249 }
250 }
251}
252
253#[cfg(test)]
254mod test {
255 use proptest::collection::vec;
256 use proptest::prelude::*;
257
258 use crate::{
259 BlindedElement, EvaluationElement, OprfClient, OprfServer, PoprfClient, PoprfServer, Proof,
260 VoprfClient, VoprfServer,
261 };
262
263 macro_rules! test_deserialize {
265 ($item:ident, $bytes:ident) => {
266 #[cfg(feature = "ristretto255")]
267 {
268 let _ = $item::<crate::Ristretto255>::deserialize(&$bytes[..]);
269 }
270
271 let _ = $item::<::p256::NistP256>::deserialize(&$bytes[..]);
272 let _ = $item::<::p384::NistP384>::deserialize(&$bytes[..]);
273 let _ = $item::<::p521::NistP521>::deserialize(&$bytes[..]);
274 };
275 }
276
277 macro_rules! test_roundtrip {
279 ($item:ident, $cs:ty, $constructor:expr) => {{
280 let original = $constructor;
281 let bytes = original.serialize();
282 let recovered = $item::<$cs>::deserialize(&bytes).expect("roundtrip deserialize");
283 assert_eq!(original.serialize(), recovered.serialize());
284 }};
285 }
286
287 macro_rules! test_trailing {
289 ($item:ident, $cs:ty, $constructor:expr) => {{
290 let original = $constructor;
291 let bytes = original.serialize();
292 let mut extended = bytes.to_vec();
293 extended.push(0x00);
294 assert!($item::<$cs>::deserialize(&extended).is_err());
295 }};
296 }
297
298 macro_rules! test_truncated {
300 ($item:ident, $cs:ty, $constructor:expr) => {{
301 let original = $constructor;
302 let bytes = original.serialize();
303 let truncated = &bytes[..bytes.len() - 1];
304 assert!($item::<$cs>::deserialize(truncated).is_err());
305 }};
306 }
307
308 proptest! {
309 #[test]
310 fn test_nocrash_oprf_client(bytes in vec(any::<u8>(), 0..200)) {
311 test_deserialize!(OprfClient, bytes);
312 }
313
314 #[test]
315 fn test_nocrash_voprf_client(bytes in vec(any::<u8>(), 0..200)) {
316 test_deserialize!(VoprfClient, bytes);
317 }
318
319 #[test]
320 fn test_nocrash_poprf_client(bytes in vec(any::<u8>(), 0..200)) {
321 test_deserialize!(PoprfClient, bytes);
322 }
323
324 #[test]
325 fn test_nocrash_oprf_server(bytes in vec(any::<u8>(), 0..200)) {
326 test_deserialize!(OprfServer, bytes);
327 }
328
329 #[test]
330 fn test_nocrash_voprf_server(bytes in vec(any::<u8>(), 0..200)) {
331 test_deserialize!(VoprfServer, bytes);
332 }
333
334 #[test]
335 fn test_nocrash_poprf_server(bytes in vec(any::<u8>(), 0..200)) {
336 test_deserialize!(PoprfServer, bytes);
337 }
338
339
340 #[test]
341 fn test_nocrash_blinded_element(bytes in vec(any::<u8>(), 0..200)) {
342 test_deserialize!(BlindedElement, bytes);
343 }
344
345 #[test]
346 fn test_nocrash_evaluation_element(bytes in vec(any::<u8>(), 0..200)) {
347 test_deserialize!(EvaluationElement, bytes);
348 }
349
350 #[test]
351 fn test_nocrash_proof(bytes in vec(any::<u8>(), 0..200)) {
352 test_deserialize!(Proof, bytes);
353 }
354 }
355
356 macro_rules! structured_tests {
357 ($cs:ty, $mod:ident) => {
358 mod $mod {
359 use super::*;
360
361 use rand::rngs::SysRng;
362
363 #[test]
364 fn roundtrip_oprf_client() {
365 let client = OprfClient::<$cs>::blind(b"input", &mut SysRng)
366 .expect("blind")
367 .state;
368 test_roundtrip!(OprfClient, $cs, client);
369 }
370
371 #[test]
372 fn roundtrip_oprf_server() {
373 let server = OprfServer::<$cs>::new(&mut SysRng).expect("new");
374 test_roundtrip!(OprfServer, $cs, server);
375 }
376
377 #[test]
378 fn roundtrip_voprf_client() {
379 let client = VoprfClient::<$cs>::blind(b"input", &mut SysRng)
380 .expect("blind")
381 .state;
382 test_roundtrip!(VoprfClient, $cs, client);
383 }
384
385 #[test]
386 fn roundtrip_voprf_server() {
387 let server = VoprfServer::<$cs>::new(&mut SysRng).expect("new");
388 test_roundtrip!(VoprfServer, $cs, server);
389 }
390
391 #[test]
392 fn roundtrip_poprf_client() {
393 let client = PoprfClient::<$cs>::blind(b"input", &mut SysRng)
394 .expect("blind")
395 .state;
396 test_roundtrip!(PoprfClient, $cs, client);
397 }
398
399 #[test]
400 fn roundtrip_poprf_server() {
401 let server = PoprfServer::<$cs>::new(&mut SysRng).expect("new");
402 test_roundtrip!(PoprfServer, $cs, server);
403 }
404
405 #[test]
406 fn trailing_oprf_client() {
407 let client = OprfClient::<$cs>::blind(b"input", &mut SysRng)
408 .expect("blind")
409 .state;
410 test_trailing!(OprfClient, $cs, client);
411 }
412
413 #[test]
414 fn trailing_oprf_server() {
415 let server = OprfServer::<$cs>::new(&mut SysRng).expect("new");
416 test_trailing!(OprfServer, $cs, server);
417 }
418
419 #[test]
420 fn truncated_oprf_client() {
421 let client = OprfClient::<$cs>::blind(b"input", &mut SysRng)
422 .expect("blind")
423 .state;
424 test_truncated!(OprfClient, $cs, client);
425 }
426
427 #[test]
428 fn truncated_oprf_server() {
429 let server = OprfServer::<$cs>::new(&mut SysRng).expect("new");
430 test_truncated!(OprfServer, $cs, server);
431 }
432
433 #[test]
434 fn empty_input_fails() {
435 assert!(OprfClient::<$cs>::deserialize(&[]).is_err());
436 assert!(OprfServer::<$cs>::deserialize(&[]).is_err());
437 assert!(VoprfClient::<$cs>::deserialize(&[]).is_err());
438 assert!(VoprfServer::<$cs>::deserialize(&[]).is_err());
439 assert!(PoprfClient::<$cs>::deserialize(&[]).is_err());
440 assert!(PoprfServer::<$cs>::deserialize(&[]).is_err());
441 assert!(BlindedElement::<$cs>::deserialize(&[]).is_err());
442 assert!(EvaluationElement::<$cs>::deserialize(&[]).is_err());
443 assert!(Proof::<$cs>::deserialize(&[]).is_err());
444 }
445 }
446 };
447 }
448
449 #[cfg(feature = "ristretto255")]
450 structured_tests!(crate::Ristretto255, ristretto255);
451 structured_tests!(::p256::NistP256, p256);
452 structured_tests!(::p384::NistP384, p384);
453 structured_tests!(::p521::NistP521, p521);
454}