diff --git a/CHANGELOG.md b/CHANGELOG.md index 1653eec3b..96e58ddcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,9 +25,11 @@ - #99 (ark-poly) Speedup `evaluate_all_lagrange_coefficients` - #100 (ark-ff) Implement `batch_inverse_and_mul` - #101 (ark-ff) Add `element(i: usize)` on the `Domain` trait. +- #107 (ark-serialize) Add an impl of `CanonicalSerialize/Deserialize` for `BTreeSet`. ### Bug fixes - #36 (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`. +- #107 (ark-serialize) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`. -## v0.0 (Initial release of arkworks/algebra) +## v0.1.0 (Initial release of arkworks/algebra) diff --git a/serialize/src/lib.rs b/serialize/src/lib.rs index 8e43bfec2..c7249d754 100644 --- a/serialize/src/lib.rs +++ b/serialize/src/lib.rs @@ -14,7 +14,7 @@ mod flags; pub use ark_std::io::{Read, Write}; use ark_std::{ borrow::{Cow, ToOwned}, - collections::BTreeMap, + collections::{BTreeMap, BTreeSet}, convert::TryFrom, vec::Vec, }; @@ -392,11 +392,6 @@ impl CanonicalSerialize for core::marker::PhantomData { fn serialized_size(&self) -> usize { 0 } - - #[inline] - fn serialize_uncompressed(&self, _writer: W) -> Result<(), SerializationError> { - Ok(()) - } } impl CanonicalDeserialize for core::marker::PhantomData { @@ -404,11 +399,6 @@ impl CanonicalDeserialize for core::marker::PhantomData { fn deserialize(_reader: R) -> Result { Ok(core::marker::PhantomData) } - - #[inline] - fn deserialize_uncompressed(_reader: R) -> Result { - Ok(core::marker::PhantomData) - } } impl<'a, T: CanonicalSerialize + ToOwned> CanonicalSerialize for Cow<'a, T> { @@ -426,6 +416,15 @@ impl<'a, T: CanonicalSerialize + ToOwned> CanonicalSerialize for Cow<'a, T> { fn serialize_uncompressed(&self, writer: W) -> Result<(), SerializationError> { self.as_ref().serialize_uncompressed(writer) } + + #[inline] + fn serialize_unchecked(&self, writer: W) -> Result<(), SerializationError> { + self.as_ref().serialize_unchecked(writer) + } + + fn uncompressed_size(&self) -> usize { + self.as_ref().uncompressed_size() + } } impl<'a, T> CanonicalDeserialize for Cow<'a, T> @@ -444,6 +443,13 @@ where reader, )?)) } + + #[inline] + fn deserialize_unchecked(reader: R) -> Result { + Ok(Cow::Owned(::Owned::deserialize_unchecked( + reader, + )?)) + } } impl CanonicalSerialize for Option { @@ -476,6 +482,26 @@ impl CanonicalSerialize for Option { Ok(()) } + + #[inline] + fn uncompressed_size(&self) -> usize { + self.is_some().uncompressed_size() + + if let Some(item) = self { + item.uncompressed_size() + } else { + 0 + } + } + + #[inline] + fn serialize_unchecked(&self, mut writer: W) -> Result<(), SerializationError> { + self.is_some().serialize_unchecked(&mut writer)?; + if let Some(item) = self { + item.serialize_unchecked(&mut writer)?; + } + + Ok(()) + } } impl CanonicalDeserialize for Option { @@ -493,7 +519,7 @@ impl CanonicalDeserialize for Option { #[inline] fn deserialize_uncompressed(mut reader: R) -> Result { - let is_some = bool::deserialize(&mut reader)?; + let is_some = bool::deserialize_uncompressed(&mut reader)?; let data = if is_some { Some(T::deserialize_uncompressed(&mut reader)?) } else { @@ -502,6 +528,18 @@ impl CanonicalDeserialize for Option { Ok(data) } + + #[inline] + fn deserialize_unchecked(mut reader: R) -> Result { + let is_some = bool::deserialize_unchecked(&mut reader)?; + let data = if is_some { + Some(T::deserialize_unchecked(&mut reader)?) + } else { + None + }; + + Ok(data) + } } impl CanonicalSerialize for bool { @@ -544,6 +582,33 @@ where .map(|(k, v)| k.serialized_size() + v.serialized_size()) .sum::() } + + fn serialize_uncompressed(&self, mut writer: W) -> Result<(), SerializationError> { + let len = self.len() as u64; + len.serialize_uncompressed(&mut writer)?; + for (k, v) in self.iter() { + k.serialize_uncompressed(&mut writer)?; + v.serialize_uncompressed(&mut writer)?; + } + Ok(()) + } + + fn serialize_unchecked(&self, mut writer: W) -> Result<(), SerializationError> { + let len = self.len() as u64; + len.serialize_unchecked(&mut writer)?; + for (k, v) in self.iter() { + k.serialize_unchecked(&mut writer)?; + v.serialize_unchecked(&mut writer)?; + } + Ok(()) + } + + fn uncompressed_size(&self) -> usize { + 8 + self + .iter() + .map(|(k, v)| k.uncompressed_size() + v.uncompressed_size()) + .sum::() + } } impl CanonicalDeserialize for BTreeMap @@ -559,11 +624,166 @@ where } Ok(map) } + + fn deserialize_uncompressed(mut reader: R) -> Result { + let len = u64::deserialize_uncompressed(&mut reader)?; + let mut map = BTreeMap::new(); + for _ in 0..len { + map.insert( + K::deserialize_uncompressed(&mut reader)?, + V::deserialize_uncompressed(&mut reader)?, + ); + } + Ok(map) + } + + fn deserialize_unchecked(mut reader: R) -> Result { + let len = u64::deserialize_unchecked(&mut reader)?; + let mut map = BTreeMap::new(); + for _ in 0..len { + map.insert( + K::deserialize_unchecked(&mut reader)?, + V::deserialize_unchecked(&mut reader)?, + ); + } + Ok(map) + } +} + +impl CanonicalSerialize for BTreeSet { + fn serialize(&self, mut writer: W) -> Result<(), SerializationError> { + let len = self.len() as u64; + len.serialize(&mut writer)?; + for elem in self.iter() { + elem.serialize(&mut writer)?; + } + Ok(()) + } + + fn serialized_size(&self) -> usize { + 8 + self + .iter() + .map(|elem| elem.serialized_size()) + .sum::() + } + + fn serialize_uncompressed(&self, mut writer: W) -> Result<(), SerializationError> { + let len = self.len() as u64; + len.serialize_uncompressed(&mut writer)?; + for elem in self.iter() { + elem.serialize_uncompressed(&mut writer)?; + } + Ok(()) + } + + fn serialize_unchecked(&self, mut writer: W) -> Result<(), SerializationError> { + let len = self.len() as u64; + len.serialize_unchecked(&mut writer)?; + for elem in self.iter() { + elem.serialize_unchecked(&mut writer)?; + } + Ok(()) + } + + fn uncompressed_size(&self) -> usize { + 8 + self + .iter() + .map(|elem| elem.uncompressed_size()) + .sum::() + } } -#[cfg(all(test, feature = "std"))] +impl CanonicalDeserialize for BTreeSet { + fn deserialize(mut reader: R) -> Result { + let len = u64::deserialize(&mut reader)?; + let mut set = BTreeSet::new(); + for _ in 0..len { + set.insert(T::deserialize(&mut reader)?); + } + Ok(set) + } + + fn deserialize_uncompressed(mut reader: R) -> Result { + let len = u64::deserialize_uncompressed(&mut reader)?; + let mut set = BTreeSet::new(); + for _ in 0..len { + set.insert(T::deserialize_uncompressed(&mut reader)?); + } + Ok(set) + } + + fn deserialize_unchecked(mut reader: R) -> Result { + let len = u64::deserialize_unchecked(&mut reader)?; + let mut set = BTreeSet::new(); + for _ in 0..len { + set.insert(T::deserialize_unchecked(&mut reader)?); + } + Ok(set) + } +} + +#[cfg(test)] mod test { use super::*; + use ark_std::vec; + + #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] + struct Dummy; + + impl CanonicalSerialize for Dummy { + #[inline] + fn serialize(&self, mut writer: W) -> Result<(), SerializationError> { + 100u8.serialize(&mut writer) + } + + #[inline] + fn serialized_size(&self) -> usize { + 100u8.serialized_size() + } + + #[inline] + fn serialize_uncompressed( + &self, + mut writer: W, + ) -> Result<(), SerializationError> { + (&[100u8, 200u8]).serialize(&mut writer) + } + + #[inline] + fn uncompressed_size(&self) -> usize { + (&[100u8, 200u8]).uncompressed_size() + } + + #[inline] + fn serialize_unchecked(&self, mut writer: W) -> Result<(), SerializationError> { + (&[100u8, 200u8]).serialize(&mut writer) + } + } + + impl CanonicalDeserialize for Dummy { + #[inline] + fn deserialize(mut reader: R) -> Result { + let result = u8::deserialize(&mut reader)?; + assert_eq!(result, 100u8); + Ok(Dummy) + } + + #[inline] + fn deserialize_uncompressed(mut reader: R) -> Result { + let result = Vec::::deserialize_uncompressed(&mut reader)?; + assert_eq!(result.as_slice(), &[100u8, 200u8]); + + Ok(Dummy) + } + + #[inline] + fn deserialize_unchecked(mut reader: R) -> Result { + let result = Vec::::deserialize_unchecked(&mut reader)?; + assert_eq!(result.as_slice(), &[100u8, 200u8]); + + Ok(Dummy) + } + } fn test_serialize< T: PartialEq + core::fmt::Debug + CanonicalSerialize + CanonicalDeserialize, @@ -603,22 +823,30 @@ mod test { #[test] fn test_tuple() { - test_serialize((123u64, 234u32, 999u16)); + test_serialize((123u64, 234u32, Dummy)); } #[test] fn test_tuple_vec() { test_serialize(vec![ - (123u64, 234u32, 999u16), - (123u64, 234u32, 999u16), - (123u64, 234u32, 999u16), + (Dummy, Dummy, Dummy), + (Dummy, Dummy, Dummy), + (Dummy, Dummy, Dummy), + ]); + test_serialize(vec![ + (86u8, 98u64, Dummy), + (86u8, 98u64, Dummy), + (86u8, 98u64, Dummy), ]); } #[test] fn test_option() { - test_serialize(Some(3u32)); - test_serialize(None::); + test_serialize(Some(Dummy)); + test_serialize(None::); + + test_serialize(Some(10u64)); + test_serialize(None::); } #[test] @@ -630,8 +858,8 @@ mod test { #[test] fn test_btreemap() { let mut map = BTreeMap::new(); - map.insert(0u64, true); - map.insert(5u64, false); + map.insert(0u64, Dummy); + map.insert(5u64, Dummy); test_serialize(map); let mut map = BTreeMap::new(); map.insert(10u64, vec![1u8, 2u8, 3u8]); @@ -639,8 +867,20 @@ mod test { test_serialize(map); } + #[test] + fn test_btreeset() { + let mut set = BTreeSet::new(); + set.insert(Dummy); + set.insert(Dummy); + test_serialize(set); + let mut set = BTreeSet::new(); + set.insert(vec![1u8, 2u8, 3u8]); + set.insert(vec![4u8, 5u8, 6u8]); + test_serialize(set); + } + #[test] fn test_phantomdata() { - test_serialize(core::marker::PhantomData::); + test_serialize(core::marker::PhantomData::); } }