Expand description
This module defines traits and implementations of cryptographic hash functions for the Diem project.
It is designed to help authors protect against two types of real world attacks:
-
Semantic Ambiguity: imagine that Alice has a private key and is using two different applications, X and Y. X asks Alice to sign a message saying “I am Alice”. Alice accepts to sign this message in the context of X. However, unbeknownst to Alice, in application Y, messages beginning with the letter “I” represent transfers. “ am “ represents a transfer of 500 coins and “Alice” can be interpreted as a destination address. When Alice signed the message she needed to be aware of how other applications might interpret that message.
-
Format Ambiguity: imagine a program that hashes a pair of strings. To hash the strings
a
andb
it hashesa + "||" + b
. The pair of stringsa="foo||", b = "bar"
anda="foo", b = "||bar"
result in the same input to the hash function and therefore the same hash. This creates a collision.
Regarding (1), this library makes it easy for Diem developers to create as many new “hashable” Rust types as needed so that each Rust type hashed and signed in Diem has a unique meaning, that is, unambiguously captures the intent of a signer.
Regarding (2), this library provides the CryptoHasher
abstraction to
easily manage cryptographic seeds for hashing. Hashing seeds aim to ensure
that the hashes of values of a given type MyNewStruct
never collide with
hashes of values from another type.
Finally, to prevent format ambiguity within a same type MyNewStruct
and
facilitate protocol specifications, we use Binary Canonical Serialization (BCS)
as the recommended solution to write Rust values into a hasher.
§Quick Start
To obtain a hash()
method for any new type MyNewStruct
, it is (strongly)
recommended to use the derive macros of serde
and diem_crypto_derive
as
follows:
use diem_crypto::hash::CryptoHash;
use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, CryptoHasher, BCSCryptoHash)]
struct MyNewStruct {/* ... */}
let value = MyNewStruct { /*...*/ };
value.hash();
Under the hood, this will generate a new implementation MyNewStructHasher
for the trait CryptoHasher
and implement the trait CryptoHash
for
MyNewStruct
using BCS.
§Implementing New Hashers
The trait CryptoHasher
captures the notion of a pre-seeded hash function,
aka a “hasher”. New implementations can be defined in two ways.
§Derive macro (recommended)
For any new structure MyNewStruct
that needs to be hashed, it is
recommended to simply use the derive macro CryptoHasher
.
use diem_crypto_derive::CryptoHasher;
use serde::Deserialize;
#[derive(Deserialize, CryptoHasher)]
#[serde(rename = "OptionalCustomSerdeName")]
struct MyNewStruct {/* ... */}
The macro CryptoHasher
will define a hasher automatically called
MyNewStructHasher
, and derive a salt using the name of the type as seen by
the Serde library. In the example above, this name was changed using the
Serde parameter rename
: the salt will be based on the value
OptionalCustomSerdeName
instead of the default name MyNewStruct
.
§Customized hashers
IMPORTANT: Do NOT use this for new code unless you know what you are doing.
This library also provides a few customized hashers defined in the code as follows:
define_hasher! { (MyNewDataHasher, MY_NEW_DATA_HASHER, MY_NEW_DATA_SEED,
b"MyUniqueSaltString") }
§Using a hasher directly
IMPORTANT: Do NOT use this for new code unless you know what you are doing.
use diem_crypto::hash::{CryptoHasher, TestOnlyHasher};
let mut hasher = TestOnlyHasher::default();
hasher.update("Test message".as_bytes());
let hash_value = hasher.finish();
Structs§
- Event
Accumulator Hasher - The hasher used to compute the hash of an internal node in the event accumulator.
- Hash
Value - Output value of our hash function. Intentionally opaque for safety and modularity.
- Hash
Value BitIterator - An iterator over
HashValue
that generates one bit for each iteration. - Hash
Value Parse Error - Parse error when attempting to construct a HashValue
- Sparse
Merkle Internal Hasher - The hasher used to compute the hash of an internal node in the Sparse Merkle Tree.
- Test
Only Hasher - The hasher used only for testing. It doesn’t have a salt.
- Transaction
Accumulator Hasher - The hasher used to compute the hash of an internal node in the transaction accumulator.
- Vote
Proposal Hasher - The hasher used to compute the hash of an internal node in the transaction accumulator.
Statics§
- ACCUMULATOR_
PLACEHOLDER_ HASH - Placeholder hash of
Accumulator
. - GENESIS_
BLOCK_ ID - Genesis block id is used as a parent of the very first block executed by the executor.
- PRE_
GENESIS_ BLOCK_ ID - Block id reserved as the id of parent block of the genesis block.
- SPARSE_
MERKLE_ PLACEHOLDER_ HASH - Placeholder hash of
SparseMerkleTree
.
Traits§
- Crypto
Hash - A type that can be cryptographically hashed to produce a
HashValue
. - Crypto
Hasher - A trait for representing the state of a cryptographic hasher.
- Test
Only Hash - Provides a test_only_hash() method that can be used in tests on types that
implement
serde::Serialize
.