essential_hash/
lib.rs

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
//! A minimal crate containing Essential's [`hash`] function and associated pre-hash
//! generic serialization implementation [`serialize`] based on [`postcard`].

#![deny(missing_docs)]
#![deny(unsafe_code)]

use essential_types::{convert::bytes_from_word, ContentAddress, Hash, Word};
use serde::Serialize;
use sha2::Digest;

mod address_impl;
pub mod block_addr;
pub mod contract_addr;
pub mod solution_set_addr;

/// Standardized trait for creating content addresses for
/// types using the correct constructors.
pub trait Address {
    /// Produce the content address for self.
    fn content_address(&self) -> ContentAddress;
}

/// Serialize data for hashing using postcard.
///
/// This serialization format is standardized across essential crates.
/// Attempting to hash data serialized with any other serialization
/// implementation will almost certainly result in a different hash.
pub fn serialize<T: Serialize>(t: &T) -> Vec<u8> {
    postcard::to_allocvec(t).expect("`postcard`'s `Serializer` implementation should never fail")
}

/// Hash data using SHA-256.
///
/// Internally, this first serializes the given type using [`serialize`] then
/// hashes the resulting slice of bytes using the `Sha256` digest.
pub fn hash<T: Serialize>(t: &T) -> Hash {
    let data = serialize(t);
    let mut hasher = <sha2::Sha256 as sha2::Digest>::new();
    hasher.update(&data);
    hasher.finalize().into()
}

/// Shorthand for hashing the given value in order to produce its content address.
///
/// Commonly useful for solutions, predicates and contracts.
pub fn content_addr<T: Address>(t: &T) -> ContentAddress {
    t.content_address()
}

/// Hash words in the same way that `Crypto::Sha256` does.
pub fn hash_words(words: &[Word]) -> Hash {
    let data = words
        .iter()
        .copied()
        .flat_map(bytes_from_word)
        .collect::<Vec<_>>();
    let mut hasher = <sha2::Sha256 as sha2::Digest>::new();
    hasher.update(&data);
    hasher.finalize().into()
}

/// Hash bytes without serializing them.
pub fn hash_bytes(bytes: &[u8]) -> Hash {
    let mut hasher = <sha2::Sha256 as sha2::Digest>::new();
    hasher.update(bytes);
    hasher.finalize().into()
}

/// Hash bytes without serializing them.
pub fn hash_bytes_iter<'i>(iter: impl IntoIterator<Item = &'i [u8]>) -> Hash {
    let mut hasher = <sha2::Sha256 as sha2::Digest>::new();
    for bytes in iter {
        hasher.update(bytes);
    }
    hasher.finalize().into()
}