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
// License: see LICENSE file at root directory of `master` branch

//! # Hash functions

use {
    core::fmt::{self, Display, Formatter},

    crate::Keccak,

    super::bits::Bits,
};

/// # Hash functions
///
/// This is used to make new [`Keccak`][struct:Keccak].
///
/// [struct:Keccak]: struct.Keccak.html
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum Hash {

    /// # SHA3-224
    Sha3_224,

    /// # SHA3-256
    Sha3_256,

    /// # SHA3-384
    Sha3_384,

    /// # SHA3-512
    Sha3_512,

    /// # SHAKE128
    Shake128,

    /// # SHAKE256
    Shake256,

}

impl Hash {

    /// # Name of this instance
    pub fn name(&self) -> &str {
        match self {
            Hash::Sha3_224 => "SHA3-224",
            Hash::Sha3_256 => "SHA3-256",
            Hash::Sha3_384 => "SHA3-384",
            Hash::Sha3_512 => "SHA3-512",
            Hash::Shake128 => "SHAKE128",
            Hash::Shake256 => "SHAKE256",
        }
    }

    /// # Makes new [`Keccak`][struct:Keccak] from this instance
    ///
    /// [struct:Keccak]: struct.Keccak.html
    pub fn new_keccak(&self) -> Keccak {
        Keccak::new(self.clone())
    }

    /// # Capacity
    pub (crate) const fn capacity(&self) -> usize {
        match self {
            Hash::Sha3_224 => 448,
            Hash::Sha3_256 => 512,
            Hash::Sha3_384 => 768,
            Hash::Sha3_512 => 1024,
            Hash::Shake128 => 256,
            Hash::Shake256 => 512,
        }
    }

    /// # Output bytes
    pub (crate) const fn output_bytes(&self) -> usize {
        match self {
            Hash::Sha3_224 => 28,
            Hash::Sha3_256 => 32,
            Hash::Sha3_384 => 48,
            Hash::Sha3_512 => 64,
            Hash::Shake128 => 16,
            Hash::Shake256 => 32,
        }
    }

    /// # Suffix (to be added to message)
    pub (crate) const fn suffix(&self) -> &[bool] {
        match self {
            Hash::Sha3_224 => &[false, true],
            Hash::Sha3_256 => &[false, true],
            Hash::Sha3_384 => &[false, true],
            Hash::Sha3_512 => &[false, true],
            Hash::Shake128 => &[true, true, true, true],
            Hash::Shake256 => &[true, true, true, true],
        }
    }

    /// # Rate
    pub (crate) const fn rate(&self) -> usize {
        Bits::B1600.bits() - self.capacity()
    }

}

impl Display for Hash {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        f.write_str(self.name())
    }

}

#[test]
fn test_hashes() {
    for h in &[Hash::Sha3_224, Hash::Sha3_256, Hash::Sha3_384, Hash::Sha3_512, Hash::Shake128, Hash::Shake256] {
        assert!(h.capacity() < Bits::B1600.bits());
        assert_eq!(h.output_bytes().checked_mul(16).unwrap(), h.capacity());

        let capacity = h.capacity();
        assert!(capacity > 0 && capacity % 64 == 0);

        let rate = h.rate();
        assert!(rate > 0 && rate % 64 == 0);
    }
}