ark_serialize/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(
3    unused,
4    future_incompatible,
5    nonstandard_style,
6    rust_2018_idioms,
7    rust_2021_compatibility
8)]
9#![forbid(unsafe_code)]
10#![doc = include_str!("../README.md")]
11mod error;
12mod flags;
13mod impls;
14
15pub use ark_std::io::{Read, Write};
16
17pub use error::*;
18pub use flags::*;
19
20#[cfg(test)]
21mod test;
22
23#[cfg(feature = "derive")]
24#[doc(hidden)]
25pub use ark_serialize_derive::*;
26
27use digest::{generic_array::GenericArray, Digest, OutputSizeUser};
28
29/// Serializes the given `CanonicalSerialize` items in sequence. `serialize_to_vec![a, b, c, d, e]`
30/// is identical to the value of `buf` after `(a, b, c, d, e).serialize_compressed(&mut buf)`.
31#[macro_export]
32macro_rules! serialize_to_vec {
33    ($($x:expr),*) => ({
34        let mut buf = ::ark_std::vec![];
35        {$crate::serialize_to_vec!(@inner buf, $($x),*)}.map(|_| buf)
36    });
37
38    (@inner $buf:expr, $y:expr, $($x:expr),*) => ({
39        {
40            $crate::CanonicalSerialize::serialize_uncompressed(&$y, &mut $buf)
41        }.and({$crate::serialize_to_vec!(@inner $buf, $($x),*)})
42    });
43
44    (@inner $buf:expr, $x:expr) => ({
45        $crate::CanonicalSerialize::serialize_uncompressed(&$x, &mut $buf)
46    });
47}
48
49/// Whether to use a compressed version of the serialization algorithm. Specific behavior depends
50/// on implementation. If no compressed version exists (e.g. on `Fp`), mode is ignored.
51#[derive(Copy, Clone, PartialEq, Eq)]
52pub enum Compress {
53    Yes,
54    No,
55}
56
57/// Whether to validate the element after deserializing it. Specific behavior depends on
58/// implementation. If no validation algorithm exists (e.g. on `Fp`), mode is ignored.
59#[derive(Copy, Clone, PartialEq, Eq)]
60pub enum Validate {
61    Yes,
62    No,
63}
64
65pub trait Valid: Sized + Sync {
66    fn check(&self) -> Result<(), SerializationError>;
67
68    fn batch_check<'a>(
69        batch: impl Iterator<Item = &'a Self> + Send,
70    ) -> Result<(), SerializationError>
71    where
72        Self: 'a,
73    {
74        #[cfg(feature = "parallel")]
75        {
76            use rayon::{iter::ParallelBridge, prelude::ParallelIterator};
77            batch.par_bridge().try_for_each(|e| e.check())?;
78        }
79        #[cfg(not(feature = "parallel"))]
80        {
81            for item in batch {
82                item.check()?;
83            }
84        }
85        Ok(())
86    }
87}
88
89/// Serializer in little endian format.
90/// This trait can be derived if all fields of a struct implement
91/// `CanonicalSerialize` and the `derive` feature is enabled.
92///
93/// # Example
94/// ```
95/// // The `derive` feature must be set for the derivation to work.
96/// use ark_serialize::*;
97///
98/// # #[cfg(feature = "derive")]
99/// #[derive(CanonicalSerialize)]
100/// struct TestStruct {
101///     a: u64,
102///     b: (u64, (u64, u64)),
103/// }
104/// ```
105pub trait CanonicalSerialize {
106    /// The general serialize method that takes in customization flags.
107    fn serialize_with_mode<W: Write>(
108        &self,
109        writer: W,
110        compress: Compress,
111    ) -> Result<(), SerializationError>;
112
113    fn serialized_size(&self, compress: Compress) -> usize;
114
115    fn serialize_compressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
116        self.serialize_with_mode(writer, Compress::Yes)
117    }
118
119    fn compressed_size(&self) -> usize {
120        self.serialized_size(Compress::Yes)
121    }
122
123    fn serialize_uncompressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
124        self.serialize_with_mode(writer, Compress::No)
125    }
126
127    fn uncompressed_size(&self) -> usize {
128        self.serialized_size(Compress::No)
129    }
130}
131
132/// Deserializer in little endian format.
133/// This trait can be derived if all fields of a struct implement
134/// `CanonicalDeserialize` and the `derive` feature is enabled.
135///
136/// # Example
137/// ```
138/// // The `derive` feature must be set for the derivation to work.
139/// use ark_serialize::*;
140///
141/// # #[cfg(feature = "derive")]
142/// #[derive(CanonicalDeserialize)]
143/// struct TestStruct {
144///     a: u64,
145///     b: (u64, (u64, u64)),
146/// }
147/// ```
148pub trait CanonicalDeserialize: Valid {
149    /// The general deserialize method that takes in customization flags.
150    fn deserialize_with_mode<R: Read>(
151        reader: R,
152        compress: Compress,
153        validate: Validate,
154    ) -> Result<Self, SerializationError>;
155
156    fn deserialize_compressed<R: Read>(reader: R) -> Result<Self, SerializationError> {
157        Self::deserialize_with_mode(reader, Compress::Yes, Validate::Yes)
158    }
159
160    fn deserialize_compressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError> {
161        Self::deserialize_with_mode(reader, Compress::Yes, Validate::No)
162    }
163
164    fn deserialize_uncompressed<R: Read>(reader: R) -> Result<Self, SerializationError> {
165        Self::deserialize_with_mode(reader, Compress::No, Validate::Yes)
166    }
167
168    fn deserialize_uncompressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError> {
169        Self::deserialize_with_mode(reader, Compress::No, Validate::No)
170    }
171}
172
173/// Serializer in little endian format allowing to encode flags.
174pub trait CanonicalSerializeWithFlags: CanonicalSerialize {
175    /// Serializes `self` and `flags` into `writer`.
176    fn serialize_with_flags<W: Write, F: Flags>(
177        &self,
178        writer: W,
179        flags: F,
180    ) -> Result<(), SerializationError>;
181
182    /// Serializes `self` and `flags` into `writer`.
183    fn serialized_size_with_flags<F: Flags>(&self) -> usize;
184}
185
186/// Deserializer in little endian format allowing flags to be encoded.
187pub trait CanonicalDeserializeWithFlags: Sized {
188    /// Reads `Self` and `Flags` from `reader`.
189    /// Returns empty flags by default.
190    fn deserialize_with_flags<R: Read, F: Flags>(
191        reader: R,
192    ) -> Result<(Self, F), SerializationError>;
193}
194
195// This private struct works around Serialize taking the pre-existing
196// std::io::Write instance of most digest::Digest implementations by value
197struct HashMarshaller<'a, H: Digest>(&'a mut H);
198
199impl<'a, H: Digest> ark_std::io::Write for HashMarshaller<'a, H> {
200    #[inline]
201    fn write(&mut self, buf: &[u8]) -> ark_std::io::Result<usize> {
202        Digest::update(self.0, buf);
203        Ok(buf.len())
204    }
205
206    #[inline]
207    fn flush(&mut self) -> ark_std::io::Result<()> {
208        Ok(())
209    }
210}
211
212/// The CanonicalSerialize induces a natural way to hash the
213/// corresponding value, of which this is the convenience trait.
214pub trait CanonicalSerializeHashExt: CanonicalSerialize {
215    fn hash<H: Digest>(&self) -> GenericArray<u8, <H as OutputSizeUser>::OutputSize> {
216        let mut hasher = H::new();
217        self.serialize_compressed(HashMarshaller(&mut hasher))
218            .expect("HashMarshaller::flush should be infaillible!");
219        hasher.finalize()
220    }
221
222    fn hash_uncompressed<H: Digest>(&self) -> GenericArray<u8, <H as OutputSizeUser>::OutputSize> {
223        let mut hasher = H::new();
224        self.serialize_uncompressed(HashMarshaller(&mut hasher))
225            .expect("HashMarshaller::flush should be infaillible!");
226        hasher.finalize()
227    }
228}
229
230/// CanonicalSerializeHashExt is a (blanket) extension trait of
231/// CanonicalSerialize
232impl<T: CanonicalSerialize> CanonicalSerializeHashExt for T {}
233
234#[inline]
235pub fn buffer_bit_byte_size(modulus_bits: usize) -> (usize, usize) {
236    let byte_size = buffer_byte_size(modulus_bits);
237    ((byte_size * 8), byte_size)
238}
239
240/// Converts the number of bits required to represent a number
241/// into the number of bytes required to represent it.
242#[inline]
243pub const fn buffer_byte_size(modulus_bits: usize) -> usize {
244    (modulus_bits + 7) / 8
245}