balloon_hash/
algorithm.rs

1//! Balloon algorithms (e.g. Balloon, BalloonM).
2
3use crate::{Error, Result};
4use core::{
5    fmt::{self, Display},
6    str::FromStr,
7};
8
9#[cfg(feature = "password-hash")]
10use password_hash::Ident;
11
12/// Balloon primitive type: variants of the algorithm.
13#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
14pub enum Algorithm {
15    /// Standard Balloon hashing algorithm.
16    Balloon,
17
18    /// M-core variant of the Balloon hashing algorithm.
19    ///
20    /// Supports parallelism by computing M instances of the
21    /// single-core Balloon function and XORing all the outputs.
22    BalloonM,
23}
24
25impl Default for Algorithm {
26    fn default() -> Algorithm {
27        Algorithm::BalloonM
28    }
29}
30
31impl Algorithm {
32    /// Balloon algorithm identifier
33    #[cfg(feature = "password-hash")]
34    #[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
35    pub const BALLOON_IDENT: Ident<'static> = Ident::new_unwrap("balloon");
36
37    /// BalloonM algorithm identifier
38    #[cfg(feature = "password-hash")]
39    #[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
40    pub const BALLOON_M_IDENT: Ident<'static> = Ident::new_unwrap("balloon-m");
41
42    /// Parse an [`Algorithm`] from the provided string.
43    pub fn new(id: impl AsRef<str>) -> Result<Self> {
44        id.as_ref().parse()
45    }
46
47    /// Get the identifier string for this Balloon [`Algorithm`].
48    pub fn as_str(&self) -> &str {
49        match self {
50            Algorithm::Balloon => "balloon",
51            Algorithm::BalloonM => "balloon-m",
52        }
53    }
54
55    /// Get the [`Ident`] that corresponds to this Balloon [`Algorithm`].
56    #[cfg(feature = "password-hash")]
57    #[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
58    pub fn ident(&self) -> Ident<'static> {
59        match self {
60            Algorithm::Balloon => Self::BALLOON_IDENT,
61            Algorithm::BalloonM => Self::BALLOON_M_IDENT,
62        }
63    }
64}
65
66impl AsRef<str> for Algorithm {
67    fn as_ref(&self) -> &str {
68        self.as_str()
69    }
70}
71
72impl Display for Algorithm {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.write_str(self.as_str())
75    }
76}
77
78impl FromStr for Algorithm {
79    type Err = Error;
80
81    fn from_str(s: &str) -> Result<Algorithm> {
82        match s {
83            "balloon" => Ok(Algorithm::Balloon),
84            "balloon-m" => Ok(Algorithm::BalloonM),
85            _ => Err(Error::AlgorithmInvalid),
86        }
87    }
88}
89
90#[cfg(feature = "password-hash")]
91#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
92impl From<Algorithm> for Ident<'static> {
93    fn from(alg: Algorithm) -> Ident<'static> {
94        alg.ident()
95    }
96}
97
98#[cfg(feature = "password-hash")]
99#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
100impl<'a> TryFrom<Ident<'a>> for Algorithm {
101    type Error = password_hash::Error;
102
103    fn try_from(ident: Ident<'a>) -> password_hash::Result<Algorithm> {
104        match ident {
105            Self::BALLOON_IDENT => Ok(Algorithm::Balloon),
106            Self::BALLOON_M_IDENT => Ok(Algorithm::BalloonM),
107            _ => Err(password_hash::Error::Algorithm),
108        }
109    }
110}