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