highwayhash

package module
v0.0.0-...-85fc8a2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2018 License: MIT Imports: 4 Imported by: 0

README

Godoc Reference Build Status

HighwayHash

HighwayHash is a pseudo-random-function (PRF) developed by Jyrki Alakuijala, Bill Cox and Jan Wassenberg (Google research). HighwayHash takes a 256 bit key and computes 64, 128 or 256 bit hash values of given messages.

It can be used to prevent hash-flooding attacks or authenticate short-lived messages. Additionally it can be used as a fingerprinting function. HighwayHash is not a general purpose cryptographic hash function (such as Blake2b, SHA-3 or SHA-2) and should not be used if strong collision resistance is required.

This repository contains a native Go version and optimized assembly implementations on both Intel and ARM platforms.

High performance

HighwayHash is an approximately 5x faster SIMD hash function as compared to SipHash which in itself is a fast and 'cryptographically strong' pseudo-random function designed by Aumasson and Bernstein.

HighwayHash uses a new way of mixing inputs with AVX2 multiply and permute instructions. The multiplications are 32x32 bit giving 64 bits-wide results and are therefore infeasible to reverse. Additionally permuting equalizes the distribution of the resulting bytes. The algorithm outputs digests ranging from 64 bits up to 256 bits at no extra cost.

Stable

All three output sizes of HighwayHash have been declared stable as of January 2018. This means that the hash results for any given input message are guaranteed not to change.

Installation

Install: go get -u github.com/minio/highwayhash

Intel Performance

Below are the single core results on an Intel Core i7 (3.1 GHz) for 256 bit outputs:

BenchmarkSum256_16      		  204.17 MB/s
BenchmarkSum256_64      		 1040.63 MB/s
BenchmarkSum256_1K      		 8653.30 MB/s
BenchmarkSum256_8K      		13476.07 MB/s
BenchmarkSum256_1M      		14928.71 MB/s
BenchmarkSum256_5M      		14180.04 MB/s
BenchmarkSum256_10M     		12458.65 MB/s
BenchmarkSum256_25M     		11927.25 MB/s

So for moderately sized messages it tops out at about 15 GB/sec. Also for small messages (1K) the performance is already at approximately 60% of the maximum throughput.

ARM Performance

On an 8 core 1.2 GHz ARM Cortex-A53 (running Debian 8.0 Jessie with Go 1.7.4) the following results were obtained:

Platform/CPU Write 64 Write 1024 Write 8192
ARM64 NEON 384 MB/s 955 MB/s 1053 MB/s

Note: For now just the (main) update loop is implemented in assembly, so for small messages there is still considerable overhead due to initialization and finalization.

Performance compared to other hashing techniques

On a Skylake CPU (3.0 GHz Xeon Platinum 8124M) the table below shows how HighwayHash compares to other hashing techniques for 5 MB messages (single core performance, all Golang implementations, see benchmark).

BenchmarkHighwayHash      	    	11986.98 MB/s
BenchmarkSHA256_AVX512    	    	 3552.74 MB/s
BenchmarkBlake2b          	    	  972.38 MB/s
BenchmarkSHA1             	    	  950.64 MB/s
BenchmarkMD5              	    	  684.18 MB/s
BenchmarkSHA512           	    	  562.04 MB/s
BenchmarkSHA256           	    	  383.07 MB/s

Note: the AVX512 version of SHA256 uses the multi-buffer crypto library technique as developed by Intel, more details can be found in sha256-simd.

Qualitative assessment

We have performed a 'qualitative' assessment of how HighwayHash compares to Blake2b in terms of the distribution of the checksums for varying numbers of messages. It shows that HighwayHash behaves similarly according to the following graph:

Hash Comparison Overview

More information can be found in HashCompare.

Requirements

All Go versions >= 1.7 are supported. Notice that the amd64 AVX2 implementation is only available with Go 1.8 and newer.

Contributing

Contributions are welcome, please send PRs for any enhancements.

Documentation

Overview

Package highwayhash implements the pseudo-random-function (PRF) HighwayHash. HighwayHash is a fast hash function designed to defend hash-flooding attacks or to authenticate short-lived messages.

HighwayHash is not a general purpose cryptographic hash function and does not provide (strong) collision resistance.

Index

Examples

Constants

View Source
const (
	// Size is the size of HighwayHash-256 checksum in bytes.
	Size = 32
	// Size128 is the size of HighwayHash-128 checksum in bytes.
	Size128 = 16
	// Size64 is the size of HighwayHash-64 checksum in bytes.
	Size64 = 8
)

Variables

This section is empty.

Functions

func New

func New(key []byte) (hash.Hash, error)

New returns a hash.Hash computing the HighwayHash-256 checksum. It returns a non-nil error if the key is not 32 bytes long.

Example

ExampleNew shows how to use HighwayHash-256 to compute fingerprints of files.

key, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here
if err != nil {
	fmt.Printf("Cannot decode hex key: %v", err) // add error handling
	return
}

file, err := os.Open("./README.md") // specify your file here
if err != nil {
	fmt.Printf("Failed to open the file: %v", err) // add error handling
	return
}
defer file.Close()

hash, err := New(key)
if err != nil {
	fmt.Printf("Failed to create HighwayHash instance: %v", err) // add error handling
	return
}

if _, err = io.Copy(hash, file); err != nil {
	fmt.Printf("Failed to read from file: %v", err) // add error handling
	return
}

checksum := hash.Sum(nil)
fmt.Println(hex.EncodeToString(checksum))
Output:

23645892b383f1bcf83e0c01e7da885499029af7512c1fd26ff3e0db4b57525a

func New128

func New128(key []byte) (hash.Hash, error)

New128 returns a hash.Hash computing the HighwayHash-128 checksum. It returns a non-nil error if the key is not 32 bytes long.

func New64

func New64(key []byte) (hash.Hash64, error)

New64 returns a hash.Hash computing the HighwayHash-64 checksum. It returns a non-nil error if the key is not 32 bytes long.

Example

ExampleNew64 shows how to use HighwayHash-64 to implement a content-addressable storage.

key, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here
if err != nil {
	fmt.Printf("Cannot decode hex key: %v", err) // add error handling
	return
}

AddressOf := func(key []byte, file string) (uint64, error) { // function to compute address based on content
	fsocket, err := os.Open(file)
	if err != nil {
		return 0, err
	}
	defer fsocket.Close()

	hash, err := New64(key)
	if err != nil {
		return 0, err
	}

	_, err = io.Copy(hash, fsocket)
	return hash.Sum64(), err
}

dir, err := ioutil.ReadDir(".")
if err != nil {
	fmt.Printf("Failed to read current directory: %v", err) // add error handling
	return
}

lookupMap := make(map[uint64]string, len(dir))
for _, file := range dir {
	if file.IsDir() {
		continue // skip sub-directroies in our example
	}
	address, err := AddressOf(key, file.Name())
	if err != nil {
		fmt.Printf("Failed to read file %s: %v", file.Name(), err) // add error handling
		return
	}
	lookupMap[address] = file.Name()
}
Output:

func Sum

func Sum(data, key []byte) [Size]byte

Sum computes the HighwayHash-256 checksum of data. It panics if the key is not 32 bytes long.

func Sum128

func Sum128(data, key []byte) [Size128]byte

Sum128 computes the HighwayHash-128 checksum of data. It panics if the key is not 32 bytes long.

func Sum64

func Sum64(data, key []byte) uint64

Sum64 computes the HighwayHash-64 checksum of data. It panics if the key is not 32 bytes long.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL