Skip to content

Commit

Permalink
Implement serde for Odd (#604)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdplm authored Jun 5, 2024
1 parent 5167b12 commit 876b125
Showing 1 changed file with 96 additions and 0 deletions.
96 changes: 96 additions & 0 deletions src/odd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -153,6 +161,30 @@ impl Odd<BoxedUint> {
}
}

#[cfg(feature = "serde")]
impl<'de, T: Deserialize<'de> + Integer + Zero> Deserialize<'de> for Odd<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: T = T::deserialize(deserializer)?;
Option::<Self>::from(Self::new(value)).ok_or(D::Error::invalid_value(
Unexpected::Other("even"),
&"a non-zero odd value",
))
}
}

#[cfg(feature = "serde")]
impl<T: Serialize + Zero> Serialize for Odd<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}

#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
Expand All @@ -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::<Odd<U64>>(&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::<Odd<U128>>(&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::<Odd<U64>>(&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::<Odd<U128>>(&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<U128> into an Odd<U64>, 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::<Odd<U64>>(&three_ser).unwrap();

assert_eq!(
smaller,
Odd::new(U64::from_u64(0x3333333333333333)).unwrap()
);
}
}
}

0 comments on commit 876b125

Please sign in to comment.