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::{CryptoHasher, BCSCryptoHash};
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
- The hasher used to compute the hash of an internal node in the event accumulator.
- Output value of our hash function. Intentionally opaque for safety and modularity.
- An iterator over
HashValue
that generates one bit for each iteration. - Parse error when attempting to construct a HashValue
- The hasher used to compute the hash of an internal node in the Sparse Merkle Tree.
- The hasher used only for testing. It doesn’t have a salt.
- The hasher used to compute the hash of an internal node in the transaction accumulator.
- The hasher used to compute the hash of an internal node in the transaction accumulator.
Statics
- Placeholder hash of
Accumulator
. - Genesis block id is used as a parent of the very first block executed by the executor.
- Block id reserved as the id of parent block of the genesis block.
- Placeholder hash of
SparseMerkleTree
.
Traits
- A type that can be cryptographically hashed to produce a
HashValue
. - A trait for representing the state of a cryptographic hasher.
- Provides a test_only_hash() method that can be used in tests on types that implement
serde::Serialize
.