snarkvm_utilities/serialize/
traits.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::SerializationError;
17pub use crate::io::{Read, Write};
18
19use serde::de::{self, DeserializeOwned, Deserializer};
20
21/// Represents metadata to be appended to an object's serialization. For
22/// example, when serializing elliptic curve points, one can
23/// use a `Flag` to represent whether the serialization is the point
24/// at infinity, or whether the `y` coordinate is positive or not.
25/// These bits will be appended to the end of the point's serialization,
26/// or included in a new byte, depending on space available.
27///
28/// This is meant to be provided to `CanonicalSerializeWithFlags` and
29/// `CanonicalDeserializeWithFlags`
30pub trait Flags: Default + Clone + Copy + Sized {
31    /// The number of bits required to encode `Self`.
32    /// This should be at most 8.
33    const BIT_SIZE: usize;
34
35    // Returns a bit mask corresponding to `self`.
36    // For example, if `Self` contains two variants, there are just two possible
37    // bit masks: `0` and `1 << 7`.
38    fn u8_bitmask(&self) -> u8;
39
40    // Tries to read `Self` from `value`. Should return `None` if the `Self::BIT_SIZE`
41    // most-significant bits of `value` do not correspond to those generated by
42    // `u8_bitmask`.
43    //
44    // That is, this method ignores all but the top `Self::BIT_SIZE` bits, and
45    // decides whether these top bits correspond to a bitmask output by `u8_bitmask`.
46    fn from_u8(value: u8) -> Option<Self>;
47
48    // Convenience method that reads `Self` from `value`, just like `Self::from_u8`, but
49    // additionally zeroes out the bits corresponding to the resulting flag in `value`.
50    // If `Self::from_u8(*value)` would return `None`, then this method should
51    // *not* modify `value`.
52    fn from_u8_remove_flags(value: &mut u8) -> Option<Self> {
53        let flags = Self::from_u8(*value);
54        if let Some(f) = flags {
55            *value &= !f.u8_bitmask();
56        }
57        flags
58    }
59}
60
61#[derive(Copy, Clone, PartialEq, Eq)]
62pub enum Compress {
63    Yes,
64    No,
65}
66
67#[derive(Copy, Clone, PartialEq, Eq)]
68pub enum Validate {
69    Yes,
70    No,
71}
72
73pub trait Valid: Sized + Sync {
74    fn check(&self) -> Result<(), SerializationError>;
75
76    fn batch_check<'a>(batch: impl Iterator<Item = &'a Self> + Send) -> Result<(), SerializationError>
77    where
78        Self: 'a,
79    {
80        #[cfg(not(feature = "serial"))]
81        {
82            use rayon::{iter::ParallelBridge, prelude::ParallelIterator};
83            batch.par_bridge().try_for_each(|e| e.check())?;
84        }
85        #[cfg(feature = "serial")]
86        {
87            for item in batch {
88                item.check()?;
89            }
90        }
91        Ok(())
92    }
93}
94
95/// Serializer in little endian format.
96/// This trait can be derived if all fields of a struct implement
97/// `CanonicalSerialize` and the `derive` feature is enabled.
98///
99/// # Example
100/// ```
101/// // The `derive` feature must be set for the derivation to work.
102/// use snarkvm_utilities::serialize::*;
103///
104/// # #[cfg(feature = "derive")]
105/// #[derive(CanonicalSerialize)]
106/// struct TestStruct {
107///     a: u64,
108///     b: (u64, (u64, u64)),
109/// }
110/// ```
111pub trait CanonicalSerialize {
112    fn serialize_with_mode<W: Write>(&self, writer: W, compress: Compress) -> Result<(), SerializationError>;
113
114    fn serialized_size(&self, compress: Compress) -> usize;
115
116    fn serialize_compressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
117        self.serialize_with_mode(writer, Compress::Yes)
118    }
119
120    fn compressed_size(&self) -> usize {
121        self.serialized_size(Compress::Yes)
122    }
123
124    fn serialize_uncompressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
125        self.serialize_with_mode(writer, Compress::No)
126    }
127
128    fn uncompressed_size(&self) -> usize {
129        self.serialized_size(Compress::No)
130    }
131}
132
133/// Deserializer in little endian format.
134/// This trait can be derived if all fields of a struct implement
135/// `CanonicalDeserialize` and the `derive` feature is enabled.
136///
137/// # Example
138/// ```
139/// // The `derive` feature must be set for the derivation to work.
140/// use snarkvm_utilities::serialize::*;
141///
142/// # #[cfg(feature = "derive")]
143/// #[derive(CanonicalDeserialize)]
144/// struct TestStruct {
145///     a: u64,
146///     b: (u64, (u64, u64)),
147/// }
148/// ```
149pub trait CanonicalDeserialize: Valid {
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>(&self, writer: W, flags: F) -> Result<(), SerializationError>;
177
178    /// Serializes `self` and `flags` into `writer`.
179    fn serialized_size_with_flags<F: Flags>(&self) -> usize;
180}
181
182/// Deserializer in little endian format allowing flags to be encoded.
183pub trait CanonicalDeserializeWithFlags: Sized {
184    /// Reads `Self` and `Flags` from `reader`.
185    /// Returns empty flags by default.
186    fn deserialize_with_flags<R: Read, F: Flags>(reader: R) -> Result<(Self, F), SerializationError>;
187}
188
189/// A helper trait used to simplify value extraction.
190pub trait DeserializeExt<'de>
191where
192    Self: DeserializeOwned,
193{
194    fn take_from_value<D: Deserializer<'de>>(value: &mut serde_json::Value, field: &str) -> Result<Self, D::Error>;
195}
196
197impl<'de, T> DeserializeExt<'de> for T
198where
199    T: DeserializeOwned,
200{
201    fn take_from_value<D: Deserializer<'de>>(value: &mut serde_json::Value, field: &str) -> Result<Self, D::Error> {
202        serde_json::from_value(
203            value.get_mut(field).ok_or_else(|| de::Error::custom(format!("The \"{field}\" field is missing")))?.take(),
204        )
205        .map_err(de::Error::custom)
206    }
207}