diff --git a/src/odd.rs b/src/odd.rs index 7ba5f73e..5fbc2c82 100644 --- a/src/odd.rs +++ b/src/odd.rs @@ -13,6 +13,14 @@ use {crate::Random, rand_core::CryptoRngCore}; #[cfg(all(feature = "alloc", feature = "rand_core"))] use crate::RandomBits; +#[cfg(feature = "serde")] +use crate::Zero; +#[cfg(feature = "serde")] +use serdect::serde::{ + de::{Error, Unexpected}, + Deserialize, Deserializer, Serialize, Serializer, +}; + /// Wrapper type for odd integers. /// /// These are frequently used in cryptography, e.g. as a modulus. @@ -153,6 +161,30 @@ impl Odd { } } +#[cfg(feature = "serde")] +impl<'de, T: Deserialize<'de> + Integer + Zero> Deserialize<'de> for Odd { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: T = T::deserialize(deserializer)?; + Option::::from(Self::new(value)).ok_or(D::Error::invalid_value( + Unexpected::Other("even"), + &"a non-zero odd value", + )) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Odd { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + #[cfg(test)] mod tests { #[cfg(feature = "alloc")] @@ -175,4 +207,68 @@ mod tests { let two = Odd::new(BoxedUint::from(2u8)); assert!(bool::from(two.is_none())); } + + #[cfg(feature = "serde")] + mod serde_tests { + use crate::{Odd, U128, U64}; + use alloc::string::ToString; + use bincode::ErrorKind; + + #[test] + fn roundtrip() { + let uint = Odd::new(U64::from_u64(0x00123)).unwrap(); + let ser = bincode::serialize(&uint).unwrap(); + let deser = bincode::deserialize::>(&ser).unwrap(); + + assert_eq!(uint, deser); + } + + #[test] + fn even_values_do_not_deserialize() { + let two = U128::from_u64(0x2); + let two_ser = bincode::serialize(&two).unwrap(); + assert!(matches!( + *bincode::deserialize::>(&two_ser).unwrap_err(), + ErrorKind::Custom(mess) if mess == "invalid value: even, expected a non-zero odd value" + )) + } + + #[test] + fn zero_does_not_deserialize() { + let zero = U64::ZERO; + let zero_ser = bincode::serialize(&zero).unwrap(); + + assert!(matches!( + *bincode::deserialize::>(&zero_ser).unwrap_err(), + ErrorKind::Custom(mess) if mess == "invalid value: even, expected a non-zero odd value" + )) + } + + #[test] + fn cannot_deserialize_into_bigger_type() { + let three = Odd::new(U64::from_u64(0x3)).unwrap(); + let three_ser = bincode::serialize(&three).unwrap(); + let error_message = bincode::deserialize::>(&three_ser) + .unwrap_err() + .to_string(); + + assert_eq!(&error_message, "io error: unexpected end of file"); + } + + // @reviewers: I expected an error when deserializing an Odd into an Odd, instead I get a truncated number. Is this a big or known limitation? + #[test] + fn silently_coerces_bigger_type_into_smaller_type() { + let three = Odd::new(U128::from_u128(0x77777777777777773333333333333333)).unwrap(); + + let three_ser = bincode::serialize(&three).unwrap(); + + // This doesn't fail, which is unexpected + let smaller = bincode::deserialize::>(&three_ser).unwrap(); + + assert_eq!( + smaller, + Odd::new(U64::from_u64(0x3333333333333333)).unwrap() + ); + } + } }