Module diem_crypto::hash

source ·
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:

  1. 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.

  2. Format Ambiguity: imagine a program that hashes a pair of strings. To hash the strings a and b it hashes a + "||" + b. The pair of strings a="foo||", b = "bar" and a="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.

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

Statics

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.