[][src]Module libra_crypto::hash

This module defines traits and implementations of cryptographic hash functions for the Libra 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 Libra developers to create as many new "hashable" Rust types as needed so that each Rust type hashed and signed in Libra 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 Libra Canonical Serialization (LCS) 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 libra_crypto_derive as follows:

use libra_crypto::hash::CryptoHash;
use libra_crypto_derive::{CryptoHasher, LCSCryptoHash};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, CryptoHasher, LCSCryptoHash)]
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 LCS.

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 libra_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 libra_crypto::hash::{CryptoHasher, TestOnlyHasher};

let mut hasher = TestOnlyHasher::default();
hasher.update("Test message".as_bytes());
let hash_value = hasher.finish();

Structs

EventAccumulatorHasher

The hasher used to compute the hash of an internal node in the event accumulator.

HashValue

Output value of our hash function. Intentionally opaque for safety and modularity.

HashValueBitIterator

An iterator over HashValue that generates one bit for each iteration.

SparseMerkleInternalHasher

The hasher used to compute the hash of an internal node in the Sparse Merkle Tree.

TestOnlyHasher

The hasher used only for testing. It doesn't have a salt.

TransactionAccumulatorHasher

The hasher used to compute the hash of an internal node in the transaction accumulator.

VoteProposalHasher

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

CryptoHash

A type that can be cryptographically hashed to produce a HashValue.

CryptoHasher

A trait for representing the state of a cryptographic hasher.

TestOnlyHash

Provides a test_only_hash() method that can be used in tests on types that implement serde::Serialize.