key_share/valid.rs
1use core::fmt;
2
3/// Validated value
4///
5/// `Valid<T>` wraps a value `T` that has been validated using [`Validate`] trait.
6///
7/// `Valid<T>` provides only immutable access to `T`. For instance, if you want to change content of `T`, you
8/// need to [deconstruct](Valid::into_inner) it, do necessary modifications, and then validate it again.
9///
10/// ## Transitive "valideness" through `AsRef`
11/// `Valid<T>` assumes that if `T` implements `AsRef<K>` and `K` can be validated (i.e. `K` implements [`Validate`]),
12/// then `K` has been validated when `T` was validated. Thus, if you have value of type `Valid<T>`, you can obtain
13/// `&Valid<K>` via `AsRef` trait.
14///
15/// Example of transitive valideness is demostrated below:
16/// ```rust
17/// use key_share::{Validate, Valid};
18///
19/// pub type CoreKeyShare = Valid<DirtyCoreKeyShare>;
20/// pub type KeyInfo = Valid<DirtyKeyInfo>;
21/// # use key_share::InvalidCoreShare as InvalidKeyShare;
22///
23/// # type SecretScalar = u128;
24/// pub struct DirtyCoreKeyShare {
25///     i: u16,
26///     key_info: DirtyKeyInfo,
27///     x: SecretScalar,
28/// }
29/// pub struct DirtyKeyInfo { /* ... */ }
30///
31/// // Key info can be validated separately
32/// impl Validate for DirtyKeyInfo {
33///     type Error = InvalidKeyShare;
34///     fn is_valid(&self) -> Result<(), Self::Error> {
35///         // ...
36///         # Ok(())
37///     }
38/// }
39///
40/// // CoreKeyShare can be validated as well
41/// impl Validate for DirtyCoreKeyShare {
42///     type Error = InvalidKeyShare;
43///     fn is_valid(&self) -> Result<(), Self::Error> {
44///         // Since `key_info` is part of key share, it **must be** validated when
45///         // the key share is validated
46///         self.key_info.is_valid();
47///         // ...
48///         # Ok(())
49///     }
50/// }
51/// impl AsRef<DirtyKeyInfo> for DirtyCoreKeyShare {
52///     fn as_ref(&self) -> &DirtyKeyInfo {
53///         &self.key_info
54///     }
55/// }
56///
57/// # let (i, key_info, x) = (0, DirtyKeyInfo {}, 42);
58/// let key_share: CoreKeyShare = DirtyCoreKeyShare { i, key_info, x }.validate()?;
59///
60/// // Since `key_share` is validated, and it contains `key_info`, we can obtain a `&KeyInfo`.
61/// // `Valid<T>` trusts that `<DirtyCoreKeyShare as Validate>::is_valid` has validated `key_info`.
62/// let key_info: &KeyInfo = key_share.as_ref();
63/// #
64/// # Ok::<_, Box<dyn std::error::Error>>(())
65/// ```
66///
67/// This mechanism allow to improve performance by not validating what's already been validated. However, incorrect
68/// implementation of `Validate` trait may lead to obtaining `Valid<K>` that's actually invalid. It may, in return,
69/// lead to runtime panic and/or compromised security of the application. Make sure that all implementations of
70/// [`Validate`] trait are correct and aligned with `AsRef` implementations.
71#[derive(Debug, Clone)]
72#[repr(transparent)]
73pub struct Valid<T>(T);
74
75impl<T> Valid<T>
76where
77    T: Validate,
78{
79    /// Validates the value
80    ///
81    /// If value is valid, returns `Ok(validated_value)` wrapped into type guard [`Valid<T>`](Valid), otherwise returns
82    /// `Err(err)` containing the error and the invalid value.
83    pub fn validate(value: T) -> Result<Self, ValidateError<T, <T as Validate>::Error>> {
84        if let Err(err) = value.is_valid() {
85            Err(ValidateError {
86                invalid_value: value,
87                error: err,
88            })
89        } else {
90            Ok(Self(value))
91        }
92    }
93
94    /// Validates a reference to value `&T` returning `&Valid<T>` if it's valid
95    pub fn validate_ref(value: &T) -> Result<&Self, ValidateError<&T, <T as Validate>::Error>> {
96        if let Err(err) = value.is_valid() {
97            Err(ValidateError {
98                invalid_value: value,
99                error: err,
100            })
101        } else {
102            Ok(Self::from_ref_unchecked(value))
103        }
104    }
105
106    /// Constructs and validates value from parts
107    ///
108    /// Refer to [`ValidateFromParts`] trait documentation
109    pub fn from_parts<Parts>(
110        parts: Parts,
111    ) -> Result<Self, ValidateError<Parts, <T as Validate>::Error>>
112    where
113        T: ValidateFromParts<Parts>,
114    {
115        if let Err(err) = T::validate_parts(&parts) {
116            Err(ValidateError {
117                invalid_value: parts,
118                error: err,
119            })
120        } else {
121            Ok(Self(T::from_parts(parts)))
122        }
123    }
124
125    /// Constructs `&Valid<T>` from `&T`, assumes that `T` has been validated
126    ///
127    /// Performs a debug assertion that `T` is validated
128    fn from_ref_unchecked(value: &T) -> &Self {
129        #[cfg(debug_assertions)]
130        #[allow(clippy::expect_used)]
131        value
132            .is_valid()
133            .expect("debug assertions: value is invalid, but was assumed to be valid");
134
135        // SAFETY: &T and &Valid<T> have exactly the same in-memory representation
136        // thanks to `repr(transparent)`, so it's sound to transmute the references.
137        // Note also that input and output references have exactly the same lifetime.
138        unsafe { core::mem::transmute(value) }
139    }
140}
141
142impl<T> Valid<T> {
143    /// Returns wraped validated value
144    pub fn into_inner(self) -> T {
145        self.0
146    }
147}
148
149impl<T> AsRef<T> for Valid<T> {
150    fn as_ref(&self) -> &T {
151        &self.0
152    }
153}
154
155impl<T> core::ops::Deref for Valid<T> {
156    type Target = T;
157    fn deref(&self) -> &Self::Target {
158        &self.0
159    }
160}
161
162impl<T, K> AsRef<Valid<K>> for Valid<T>
163where
164    T: Validate + AsRef<K>,
165    K: Validate,
166{
167    fn as_ref(&self) -> &Valid<K> {
168        let sub_value = self.0.as_ref();
169        Valid::from_ref_unchecked(sub_value)
170    }
171}
172
173/// Represents a type that can be validated
174pub trait Validate {
175    /// Validation error
176    type Error: fmt::Debug;
177
178    /// Checks whether value is valid
179    ///
180    /// Returns `Ok(())` if it's valid, otherwise returns `Err(err)`
181    fn is_valid(&self) -> Result<(), Self::Error>;
182
183    /// Validates the value
184    ///
185    /// If value is valid, returns `Ok(validated_value)` wrapped into type guard [`Valid<T>`](Valid), otherwise returns
186    /// `Err(err)` containing the error and the invalid value.
187    fn validate(self) -> Result<Valid<Self>, ValidateError<Self, Self::Error>>
188    where
189        Self: Sized,
190    {
191        Valid::validate(self)
192    }
193
194    /// Validates the value by reference
195    ///
196    /// If value is valid, returns [`&Valid<Self>`](Valid), otherwise returns validation error
197    fn validate_ref(&self) -> Result<&Valid<Self>, Self::Error>
198    where
199        Self: Sized,
200    {
201        Valid::validate_ref(self).map_err(|err| err.into_error())
202    }
203}
204
205impl<T: Validate> Validate for &T {
206    type Error = <T as Validate>::Error;
207    fn is_valid(&self) -> Result<(), Self::Error> {
208        (*self).is_valid()
209    }
210}
211
212/// Represents a type that can be constructed and validated from `Parts`
213///
214/// That can be particularly useful when vaidating `Parts` is cheaper than validating `Self`.
215///
216/// ## Example
217/// Suppose you have a struct `KeyShare` that consists of [`DirtyCoreKeyShare`](crate::DirtyCoreKeyShare) and some `AuxData`. In
218/// order to validate `KeyShare`, both core key share and aux data need to be validated separately and then they need to be
219/// checked for consistency. Now, if you already have `Valid<DirtyKeyShare>` and `Valid<AuxData>`, then you can skip their validation
220/// and only check that they're consistent.
221///
222/// ```rust
223/// use key_share::{Valid, Validate, ValidateFromParts};
224/// use generic_ec::Curve;
225///
226/// pub struct KeyShare<E: Curve> {
227///     core: key_share::DirtyCoreKeyShare<E>,
228///     aux: AuxData,
229/// }
230/// # pub struct AuxData { /* ... */ }
231/// # impl Validate for AuxData {
232/// #     type Error = std::convert::Infallible;
233/// #     fn is_valid(&self) -> Result<(), Self::Error> { Ok(()) }
234/// # }
235///
236/// # type InvalidKeyShare = Box<dyn std::error::Error>;
237/// // Validation for the whole key share can be expensive
238/// impl<E: Curve> Validate for KeyShare<E> {
239///     type Error = InvalidKeyShare;
240///     fn is_valid(&self) -> Result<(), Self::Error> {
241///         self.core.is_valid()?;
242///         self.aux.is_valid()?;
243///         check_consistency(&self.core, &self.aux)
244///     }
245/// }
246/// fn check_consistency<E: Curve>(
247///     core: &key_share::DirtyCoreKeyShare<E>,
248///     aux: &AuxData,
249/// ) -> Result<(), InvalidKeyShare> {
250///     // check that `core` and `aux` seem to match each other
251/// # Ok(())
252/// }
253///
254/// // Sometimes, we already validated that `core` and `aux` are valid, so we can perform cheaper validation:
255/// impl<E: Curve> ValidateFromParts<(Valid<key_share::DirtyCoreKeyShare<E>>, Valid<AuxData>)>
256///     for KeyShare<E>
257/// {
258///     fn validate_parts(parts: &(Valid<key_share::DirtyCoreKeyShare<E>>, Valid<AuxData>)) -> Result<(), Self::Error> {
259///         check_consistency(&parts.0, &parts.1)
260///     }
261///     fn from_parts(parts: (Valid<key_share::DirtyCoreKeyShare<E>>, Valid<AuxData>)) -> Self {
262///         Self { core: parts.0.into_inner(), aux: parts.1.into_inner() }
263///     }
264/// }
265/// ```
266pub trait ValidateFromParts<Parts>: Validate {
267    /// Validates parts
268    ///
269    /// Note: implementation **must** guarantee that if `T::validate_parts(parts).is_ok()` then `T::from_parts(parts).is_valid().is_ok()`
270    fn validate_parts(parts: &Parts) -> Result<(), Self::Error>;
271    /// Constructs `Self` from parts
272    fn from_parts(parts: Parts) -> Self;
273}
274
275/// Validation error
276///
277/// Contains an error that explains why value was considered invalid, and the value itself. It can be used
278/// to reclaim ownership over invalid value.
279pub struct ValidateError<T, E> {
280    invalid_value: T,
281    error: E,
282}
283
284impl<T, E> ValidateError<T, E> {
285    /// Returns reference to value that did not pass validation
286    pub fn invalid_value(&self) -> &T {
287        &self.invalid_value
288    }
289
290    /// Returns error explaining why value was considered invalid
291    pub fn error(&self) -> &E {
292        &self.error
293    }
294
295    /// Reclaim ownership over invalidated value
296    pub fn into_invalid_value(self) -> T {
297        self.invalid_value
298    }
299
300    /// Returns ownership over error
301    pub fn into_error(self) -> E {
302        self.error
303    }
304}
305
306impl<T, E: fmt::Debug> fmt::Debug for ValidateError<T, E> {
307    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308        f.debug_struct("ValidateError")
309            .field("error", &self.error)
310            .finish_non_exhaustive()
311    }
312}
313
314impl<T, E: fmt::Display> fmt::Display for ValidateError<T, E> {
315    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316        f.write_str("validation error")
317    }
318}
319
320#[cfg(feature = "std")]
321impl<T, E> std::error::Error for ValidateError<T, E>
322where
323    E: std::error::Error + 'static,
324{
325    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
326        Some(&self.error)
327    }
328}
329
330#[cfg(feature = "serde")]
331impl<T> serde::Serialize for Valid<T>
332where
333    T: serde::Serialize,
334{
335    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
336    where
337        S: serde::Serializer,
338    {
339        (**self).serialize(serializer)
340    }
341}
342
343#[cfg(feature = "serde")]
344impl<'de, T> serde::Deserialize<'de> for Valid<T>
345where
346    T: Validate + serde::Deserialize<'de>,
347    <T as Validate>::Error: fmt::Display,
348{
349    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
350    where
351        D: serde::Deserializer<'de>,
352    {
353        use serde::de::Error;
354        let value = T::deserialize(deserializer)?;
355        value.validate().map_err(|err| {
356            D::Error::custom(format_args!(
357                "deserialized value is invalid: {}",
358                err.error()
359            ))
360        })
361    }
362}