crypto/hashes/ternary/
mod.rs

1// Copyright 2020 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! Ternary sponge constructions.
5
6#[cfg(feature = "curl-p")]
7#[cfg_attr(docsrs, doc(cfg(feature = "curl-p")))]
8pub mod curl_p;
9
10#[cfg(feature = "kerl_deprecated_do_not_use")]
11#[cfg_attr(docsrs, doc(cfg(feature = "kerl_deprecated_do_not_use")))]
12#[cfg_attr(not(test), deprecated)]
13pub mod kerl;
14
15/// The length of a hash in units of balanced trits.
16pub const HASH_LENGTH: usize = 243;
17/// The length of a hash in trytes.
18pub const HASH_LENGTH_TRYTES: usize = 243 / 3;
19
20use core::ops::DerefMut;
21
22use crate::encoding::ternary::{raw::RawEncoding, Btrit, TritBuf, Trits, T1B1};
23
24/// The common interface of ternary cryptographic hash functions that follow the sponge construction.
25pub trait Sponge {
26    /// An error indicating that a failure has occured during a sponge operation.
27    type Error;
28
29    /// Reset the inner state of the sponge.
30    fn reset(&mut self);
31
32    /// Absorb `input` into the sponge.
33    fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error>;
34
35    /// Squeeze the sponge into `buf`.
36    fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error>;
37
38    /// Convenience function using `Sponge::squeeze_into` to return an owned output.
39    fn squeeze(&mut self) -> Result<TritBuf, Self::Error> {
40        let mut output = TritBuf::zeros(HASH_LENGTH);
41        self.squeeze_into(&mut output)?;
42        Ok(output)
43    }
44
45    /// Convenience function to absorb `input`, squeeze the sponge into `buf`, and reset the sponge.
46    fn digest_into(&mut self, input: &Trits, buf: &mut Trits) -> Result<(), Self::Error> {
47        self.absorb(input)?;
48        self.squeeze_into(buf)?;
49        self.reset();
50        Ok(())
51    }
52
53    /// Convenience function to absorb `input`, squeeze the sponge, reset the sponge and return an owned output.
54    fn digest(&mut self, input: &Trits) -> Result<TritBuf, Self::Error> {
55        self.absorb(input)?;
56        let output = self.squeeze()?;
57        self.reset();
58        Ok(output)
59    }
60}
61
62impl<T: Sponge, U: DerefMut<Target = T>> Sponge for U {
63    type Error = T::Error;
64
65    fn reset(&mut self) {
66        T::reset(self)
67    }
68
69    fn absorb(&mut self, input: &Trits) -> Result<(), Self::Error> {
70        T::absorb(self, input)
71    }
72
73    fn squeeze_into(&mut self, buf: &mut Trits) -> Result<(), Self::Error> {
74        T::squeeze_into(self, buf)
75    }
76}
77
78#[derive(Debug)]
79pub enum HashError {
80    WrongLength,
81}
82
83/// Ternary cryptographic hash.
84#[derive(Copy, Clone)]
85pub struct Hash([Btrit; HASH_LENGTH]);
86
87impl Hash {
88    /// Creates a hash filled with zeros.
89    pub fn zeros() -> Self {
90        Self([Btrit::Zero; HASH_LENGTH])
91    }
92
93    /// Interpret the `Hash` as a trit slice.
94    pub fn as_trits(&self) -> &Trits<T1B1> {
95        self
96    }
97
98    /// Interpret the `Hash` as a mutable trit slice.
99    pub fn as_trits_mut(&mut self) -> &mut Trits<T1B1> {
100        &mut *self
101    }
102
103    /// Returns the weight - number of ending 0s - of the `Hash`.
104    #[allow(clippy::cast_possible_truncation)] // `HASH_LENGTH` is smaller than `u8::MAX`.
105    pub fn weight(&self) -> u8 {
106        self.iter().rev().take_while(|t| *t == Btrit::Zero).count() as u8
107    }
108}
109
110impl<'a, T: RawEncoding<Trit = Btrit>> core::convert::TryFrom<&'a Trits<T>> for Hash {
111    type Error = HashError;
112
113    fn try_from(trits: &'a Trits<T>) -> Result<Self, Self::Error> {
114        if trits.len() == HASH_LENGTH {
115            let mut hash = Self([Btrit::Zero; HASH_LENGTH]);
116            hash.copy_from(trits);
117            Ok(hash)
118        } else {
119            Err(HashError::WrongLength)
120        }
121    }
122}
123
124impl core::ops::Deref for Hash {
125    type Target = Trits<T1B1>;
126
127    fn deref(&self) -> &Trits<T1B1> {
128        <&Trits>::from(&self.0 as &[_])
129    }
130}
131
132impl DerefMut for Hash {
133    fn deref_mut(&mut self) -> &mut Trits<T1B1> {
134        <&mut Trits>::from(&mut self.0 as &mut [_])
135    }
136}
137
138impl PartialEq for Hash {
139    fn eq(&self, other: &Self) -> bool {
140        self.as_trits() == other.as_trits()
141    }
142}
143
144impl Eq for Hash {}
145
146impl core::fmt::Display for Hash {
147    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148        core::fmt::Debug::fmt(self, f)
149    }
150}
151
152impl core::fmt::Debug for Hash {
153    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
154        write!(f, "{:?}", self.as_trits())
155    }
156}
157
158impl core::hash::Hash for Hash {
159    fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
160        self.0.hash(hasher)
161    }
162}