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}