pax_global_header00006660000000000000000000000064140271256450014520gustar00rootroot0000000000000052 comment=08ce0b4fa7932a018438133f1b632e1c674d4107 highwayhash-1.0.2/000077500000000000000000000000001402712564500140245ustar00rootroot00000000000000highwayhash-1.0.2/.github/000077500000000000000000000000001402712564500153645ustar00rootroot00000000000000highwayhash-1.0.2/.github/workflows/000077500000000000000000000000001402712564500174215ustar00rootroot00000000000000highwayhash-1.0.2/.github/workflows/codeql.yml000066400000000000000000000031351402712564500214150ustar00rootroot00000000000000name: "Code scanning - action" on: push: pull_request: schedule: - cron: '0 19 * * 0' jobs: CodeQL-Build: # CodeQL runs on ubuntu-latest and windows-latest runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 # If this run was triggered by a pull request event, then checkout # the head of the pull request instead of the merge commit. - run: git checkout HEAD^2 if: ${{ github.event_name == 'pull_request' }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # 鈩癸笍 Command-line programs to run using the OS shell. # 馃摎 https://git.io/JvXDl # 鉁忥笍 If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 highwayhash-1.0.2/.github/workflows/go.yml000066400000000000000000000025551402712564500205600ustar00rootroot00000000000000name: Go on: pull_request: branches: - master push: branches: - master jobs: build: name: Build Go ${{ matrix.go-version }} runs-on: ubuntu-latest strategy: matrix: go-version: [1.15.x, 1.16.x] steps: - name: Set up Go ${{ matrix.go-version }} uses: actions/setup-go@v1 with: go-version: ${{ matrix.go-version }} id: go - name: Check out code into the Go module directory uses: actions/checkout@v1 - name: Build env: GO111MODULE: on run: | curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.33.0 $(go env GOPATH)/bin/golangci-lint run --config ./.golangci.yml go vet ./... test: name: Testing Go ${{ matrix.go-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: go-version: [1.16.x] os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} uses: actions/setup-go@v1 with: go-version: ${{ matrix.go-version }} id: go - name: Check out code into the Go module directory uses: actions/checkout@v1 - name: Test on ${{ matrix.os }} env: GO111MODULE: on run: | go test ./... highwayhash-1.0.2/.gitignore000066400000000000000000000000061402712564500160100ustar00rootroot00000000000000*.testhighwayhash-1.0.2/.golangci.yml000066400000000000000000000012251402712564500164100ustar00rootroot00000000000000linters-settings: golint: min-confidence: 0 misspell: locale: US linters: disable-all: true enable: - typecheck - goimports - misspell - govet - golint - ineffassign - gosimple - deadcode - unparam - unused - structcheck issues: exclude-use-default: false exclude: - should have a package comment - error strings should not be capitalized or end with punctuation or a newline - should have comment # TODO(aead): Remove once all exported ident. have comments! service: golangci-lint-version: 1.20.0 # use the fixed version to not introduce new linters unexpectedly highwayhash-1.0.2/LICENSE000066400000000000000000000261361402712564500150410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. highwayhash-1.0.2/README.md000066400000000000000000000115011402712564500153010ustar00rootroot00000000000000[![Godoc Reference](https://godoc.org/github.com/minio/highwayhash?status.svg)](https://godoc.org/github.com/minio/highwayhash) [![Build Status](https://travis-ci.org/minio/highwayhash.svg?branch=master)](https://travis-ci.org/minio/highwayhash) ## HighwayHash [HighwayHash](https://github.com/google/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 for Intel, ARM and ppc64le architectures. ### High performance HighwayHash is an approximately 5x faster SIMD hash function as compared to [SipHash](https://www.131002.net/siphash/siphash.pdf) 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](https://github.com/google/highwayhash/#versioning-and-stability) 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 Below are the single core results on an EC2 m6g.4xlarge (Graviton2) instance for 256 bit outputs: ``` BenchmarkSum256_16 96.82 MB/s BenchmarkSum256_64 445.35 MB/s BenchmarkSum256_1K 2782.46 MB/s BenchmarkSum256_8K 4083.58 MB/s BenchmarkSum256_1M 4986.41 MB/s BenchmarkSum256_5M 4992.72 MB/s BenchmarkSum256_10M 4993.32 MB/s BenchmarkSum256_25M 4992.55 MB/s ``` ### ppc64le Performance The ppc64le accelerated version is roughly 10x faster compared to the non-optimized version: ``` benchmark old MB/s new MB/s speedup BenchmarkWrite_8K 531.19 5566.41 10.48x BenchmarkSum64_8K 518.86 4971.88 9.58x BenchmarkSum256_8K 502.45 4474.20 8.90x ``` ### 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](https://github.com/fwessels/HashCompare/blob/master/benchmarks_test.go)). ``` 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](https://github.com/intel/intel-ipsec-mb) technique as developed by Intel, more details can be found in [sha256-simd](https://github.com/minio/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](https://s3.amazonaws.com/s3git-assets/hash-comparison-final.png) More information can be found in [HashCompare](https://github.com/fwessels/HashCompare). ### Requirements All Go versions >= 1.11 are supported (needed for required assembly support for the different platforms). ### Contributing Contributions are welcome, please send PRs for any enhancements.highwayhash-1.0.2/examples_test.go000066400000000000000000000047541402712564500172420ustar00rootroot00000000000000// Copyright (c) 2018 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. package highwayhash import ( "encoding/hex" "fmt" "io" "io/ioutil" "os" ) // On windows the New example may fail (produce a different hash value) - e.g. // if the newline character is changed from '\n' to '\r\n'. Therefore, the New // example uses a file with a single line. // ExampleNew shows how to use HighwayHash-256 to compute fingerprints of files. func ExampleNew() { 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(".gitignore") // 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: 0a379f2bd8c9c1c6a501f3c327ce7efd10d98148d2c5c787d59b3171970daa65 } // ExampleNew64 shows how to use HighwayHash-64 to implement a content-addressable storage. func ExampleNew64() { 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: } highwayhash-1.0.2/go.mod000066400000000000000000000001521402712564500151300ustar00rootroot00000000000000module github.com/minio/highwayhash go 1.15 require golang.org/x/sys v0.0.0-20190130150945-aca44879d564 highwayhash-1.0.2/go.sum000066400000000000000000000003171402712564500151600ustar00rootroot00000000000000golang.org/x/sys v0.0.0-20190130150945-aca44879d564 h1:o6ENHFwwr1TZ9CUPQcfo1HGvLP1OPsPOTB7xCIOPNmU= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= highwayhash-1.0.2/highwayhash.go000066400000000000000000000123311402712564500166570ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // 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. package highwayhash import ( "encoding/binary" "errors" "hash" ) 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 ) var errKeySize = errors.New("highwayhash: invalid key size") // New returns a hash.Hash computing the HighwayHash-256 checksum. // It returns a non-nil error if the key is not 32 bytes long. func New(key []byte) (hash.Hash, error) { if len(key) != Size { return nil, errKeySize } h := &digest{size: Size} copy(h.key[:], key) h.Reset() return h, nil } // 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 New128(key []byte) (hash.Hash, error) { if len(key) != Size { return nil, errKeySize } h := &digest{size: Size128} copy(h.key[:], key) h.Reset() return h, nil } // New64 returns a hash.Hash computing the HighwayHash-64 checksum. // It returns a non-nil error if the key is not 32 bytes long. func New64(key []byte) (hash.Hash64, error) { if len(key) != Size { return nil, errKeySize } h := new(digest64) h.size = Size64 copy(h.key[:], key) h.Reset() return h, nil } // Sum computes the HighwayHash-256 checksum of data. // It panics if the key is not 32 bytes long. func Sum(data, key []byte) [Size]byte { if len(key) != Size { panic(errKeySize) } var state [16]uint64 initialize(&state, key) if n := len(data) & (^(Size - 1)); n > 0 { update(&state, data[:n]) data = data[n:] } if len(data) > 0 { var block [Size]byte offset := copy(block[:], data) hashBuffer(&state, &block, offset) } var hash [Size]byte finalize(hash[:], &state) return hash } // Sum128 computes the HighwayHash-128 checksum of data. // It panics if the key is not 32 bytes long. func Sum128(data, key []byte) [Size128]byte { if len(key) != Size { panic(errKeySize) } var state [16]uint64 initialize(&state, key) if n := len(data) & (^(Size - 1)); n > 0 { update(&state, data[:n]) data = data[n:] } if len(data) > 0 { var block [Size]byte offset := copy(block[:], data) hashBuffer(&state, &block, offset) } var hash [Size128]byte finalize(hash[:], &state) return hash } // Sum64 computes the HighwayHash-64 checksum of data. // It panics if the key is not 32 bytes long. func Sum64(data, key []byte) uint64 { if len(key) != Size { panic(errKeySize) } var state [16]uint64 initialize(&state, key) if n := len(data) & (^(Size - 1)); n > 0 { update(&state, data[:n]) data = data[n:] } if len(data) > 0 { var block [Size]byte offset := copy(block[:], data) hashBuffer(&state, &block, offset) } var hash [Size64]byte finalize(hash[:], &state) return binary.LittleEndian.Uint64(hash[:]) } type digest64 struct{ digest } func (d *digest64) Sum64() uint64 { state := d.state if d.offset > 0 { hashBuffer(&state, &d.buffer, d.offset) } var hash [8]byte finalize(hash[:], &state) return binary.LittleEndian.Uint64(hash[:]) } type digest struct { state [16]uint64 // v0 | v1 | mul0 | mul1 key, buffer [Size]byte offset int size int } func (d *digest) Size() int { return d.size } func (d *digest) BlockSize() int { return Size } func (d *digest) Reset() { initialize(&d.state, d.key[:]) d.offset = 0 } func (d *digest) Write(p []byte) (n int, err error) { n = len(p) if d.offset > 0 { remaining := Size - d.offset if n < remaining { d.offset += copy(d.buffer[d.offset:], p) return } copy(d.buffer[d.offset:], p[:remaining]) update(&d.state, d.buffer[:]) p = p[remaining:] d.offset = 0 } if nn := len(p) & (^(Size - 1)); nn > 0 { update(&d.state, p[:nn]) p = p[nn:] } if len(p) > 0 { d.offset = copy(d.buffer[d.offset:], p) } return } func (d *digest) Sum(b []byte) []byte { state := d.state if d.offset > 0 { hashBuffer(&state, &d.buffer, d.offset) } var hash [Size]byte finalize(hash[:d.size], &state) return append(b, hash[:d.size]...) } func hashBuffer(state *[16]uint64, buffer *[32]byte, offset int) { var block [Size]byte mod32 := (uint64(offset) << 32) + uint64(offset) for i := range state[:4] { state[i] += mod32 } for i := range state[4:8] { t0 := uint32(state[i+4]) t0 = (t0 << uint(offset)) | (t0 >> uint(32-offset)) t1 := uint32(state[i+4] >> 32) t1 = (t1 << uint(offset)) | (t1 >> uint(32-offset)) state[i+4] = (uint64(t1) << 32) | uint64(t0) } mod4 := offset & 3 remain := offset - mod4 copy(block[:], buffer[:remain]) if offset >= 16 { copy(block[28:], buffer[offset-4:]) } else if mod4 != 0 { last := uint32(buffer[remain]) last += uint32(buffer[remain+mod4>>1]) << 8 last += uint32(buffer[offset-1]) << 16 binary.LittleEndian.PutUint32(block[16:], last) } update(state, block[:]) } highwayhash-1.0.2/highwayhashAVX2_amd64.s000066400000000000000000000132021402712564500201460ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // +build amd64,!gccgo,!appengine,!nacl,!noasm #include "textflag.h" DATA 路consAVX2<>+0x00(SB)/8, $0xdbe6d5d5fe4cce2f DATA 路consAVX2<>+0x08(SB)/8, $0xa4093822299f31d0 DATA 路consAVX2<>+0x10(SB)/8, $0x13198a2e03707344 DATA 路consAVX2<>+0x18(SB)/8, $0x243f6a8885a308d3 DATA 路consAVX2<>+0x20(SB)/8, $0x3bd39e10cb0ef593 DATA 路consAVX2<>+0x28(SB)/8, $0xc0acf169b5f18a8c DATA 路consAVX2<>+0x30(SB)/8, $0xbe5466cf34e90c6c DATA 路consAVX2<>+0x38(SB)/8, $0x452821e638d01377 GLOBL 路consAVX2<>(SB), (NOPTR+RODATA), $64 DATA 路zipperMergeAVX2<>+0x00(SB)/8, $0xf010e05020c03 DATA 路zipperMergeAVX2<>+0x08(SB)/8, $0x70806090d0a040b DATA 路zipperMergeAVX2<>+0x10(SB)/8, $0xf010e05020c03 DATA 路zipperMergeAVX2<>+0x18(SB)/8, $0x70806090d0a040b GLOBL 路zipperMergeAVX2<>(SB), (NOPTR+RODATA), $32 #define REDUCE_MOD(x0, x1, x2, x3, tmp0, tmp1, y0, y1) \ MOVQ $0x3FFFFFFFFFFFFFFF, tmp0 \ ANDQ tmp0, x3 \ MOVQ x2, y0 \ MOVQ x3, y1 \ \ MOVQ x2, tmp0 \ MOVQ x3, tmp1 \ SHLQ $1, tmp1 \ SHRQ $63, tmp0 \ MOVQ tmp1, x3 \ ORQ tmp0, x3 \ \ SHLQ $1, x2 \ \ MOVQ y0, tmp0 \ MOVQ y1, tmp1 \ SHLQ $2, tmp1 \ SHRQ $62, tmp0 \ MOVQ tmp1, y1 \ ORQ tmp0, y1 \ \ SHLQ $2, y0 \ \ XORQ x0, y0 \ XORQ x2, y0 \ XORQ x1, y1 \ XORQ x3, y1 #define UPDATE(msg) \ VPADDQ msg, Y2, Y2 \ VPADDQ Y3, Y2, Y2 \ \ VPSRLQ $32, Y1, Y0 \ BYTE $0xC5; BYTE $0xFD; BYTE $0xF4; BYTE $0xC2 \ // VPMULUDQ Y2, Y0, Y0 VPXOR Y0, Y3, Y3 \ \ VPADDQ Y4, Y1, Y1 \ \ VPSRLQ $32, Y2, Y0 \ BYTE $0xC5; BYTE $0xFD; BYTE $0xF4; BYTE $0xC1 \ // VPMULUDQ Y1, Y0, Y0 VPXOR Y0, Y4, Y4 \ \ VPSHUFB Y5, Y2, Y0 \ VPADDQ Y0, Y1, Y1 \ \ VPSHUFB Y5, Y1, Y0 \ VPADDQ Y0, Y2, Y2 // func initializeAVX2(state *[16]uint64, key []byte) TEXT 路initializeAVX2(SB), 4, $0-32 MOVQ state+0(FP), AX MOVQ key_base+8(FP), BX MOVQ $路consAVX2<>(SB), CX VMOVDQU 0(BX), Y1 VPSHUFD $177, Y1, Y2 VMOVDQU 0(CX), Y3 VMOVDQU 32(CX), Y4 VPXOR Y3, Y1, Y1 VPXOR Y4, Y2, Y2 VMOVDQU Y1, 0(AX) VMOVDQU Y2, 32(AX) VMOVDQU Y3, 64(AX) VMOVDQU Y4, 96(AX) VZEROUPPER RET // func updateAVX2(state *[16]uint64, msg []byte) TEXT 路updateAVX2(SB), 4, $0-32 MOVQ state+0(FP), AX MOVQ msg_base+8(FP), BX MOVQ msg_len+16(FP), CX CMPQ CX, $32 JB DONE VMOVDQU 0(AX), Y1 VMOVDQU 32(AX), Y2 VMOVDQU 64(AX), Y3 VMOVDQU 96(AX), Y4 VMOVDQU 路zipperMergeAVX2<>(SB), Y5 LOOP: VMOVDQU 0(BX), Y0 UPDATE(Y0) ADDQ $32, BX SUBQ $32, CX JA LOOP VMOVDQU Y1, 0(AX) VMOVDQU Y2, 32(AX) VMOVDQU Y3, 64(AX) VMOVDQU Y4, 96(AX) VZEROUPPER DONE: RET // func finalizeAVX2(out []byte, state *[16]uint64) TEXT 路finalizeAVX2(SB), 4, $0-32 MOVQ state+24(FP), AX MOVQ out_base+0(FP), BX MOVQ out_len+8(FP), CX VMOVDQU 0(AX), Y1 VMOVDQU 32(AX), Y2 VMOVDQU 64(AX), Y3 VMOVDQU 96(AX), Y4 VMOVDQU 路zipperMergeAVX2<>(SB), Y5 VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) CMPQ CX, $8 JE skipUpdate // Just 4 rounds for 64-bit checksum VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) CMPQ CX, $16 JE skipUpdate // 6 rounds for 128-bit checksum VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) VPERM2I128 $1, Y1, Y1, Y0 VPSHUFD $177, Y0, Y0 UPDATE(Y0) skipUpdate: VMOVDQU Y1, 0(AX) VMOVDQU Y2, 32(AX) VMOVDQU Y3, 64(AX) VMOVDQU Y4, 96(AX) VZEROUPPER CMPQ CX, $8 JE hash64 CMPQ CX, $16 JE hash128 // 256-bit checksum MOVQ 0*8(AX), R8 MOVQ 1*8(AX), R9 MOVQ 4*8(AX), R10 MOVQ 5*8(AX), R11 ADDQ 8*8(AX), R8 ADDQ 9*8(AX), R9 ADDQ 12*8(AX), R10 ADDQ 13*8(AX), R11 REDUCE_MOD(R8, R9, R10, R11, R12, R13, R14, R15) MOVQ R14, 0(BX) MOVQ R15, 8(BX) MOVQ 2*8(AX), R8 MOVQ 3*8(AX), R9 MOVQ 6*8(AX), R10 MOVQ 7*8(AX), R11 ADDQ 10*8(AX), R8 ADDQ 11*8(AX), R9 ADDQ 14*8(AX), R10 ADDQ 15*8(AX), R11 REDUCE_MOD(R8, R9, R10, R11, R12, R13, R14, R15) MOVQ R14, 16(BX) MOVQ R15, 24(BX) RET hash128: MOVQ 0*8(AX), R8 MOVQ 1*8(AX), R9 ADDQ 6*8(AX), R8 ADDQ 7*8(AX), R9 ADDQ 8*8(AX), R8 ADDQ 9*8(AX), R9 ADDQ 14*8(AX), R8 ADDQ 15*8(AX), R9 MOVQ R8, 0(BX) MOVQ R9, 8(BX) RET hash64: MOVQ 0*8(AX), DX ADDQ 4*8(AX), DX ADDQ 8*8(AX), DX ADDQ 12*8(AX), DX MOVQ DX, 0(BX) RET highwayhash-1.0.2/highwayhash_amd64.go000066400000000000000000000024131402712564500176520ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // +build amd64,!gccgo,!appengine,!nacl,!noasm package highwayhash import "golang.org/x/sys/cpu" var ( useSSE4 = cpu.X86.HasSSE41 useAVX2 = cpu.X86.HasAVX2 useNEON = false useVMX = false ) //go:noescape func initializeSSE4(state *[16]uint64, key []byte) //go:noescape func initializeAVX2(state *[16]uint64, key []byte) //go:noescape func updateSSE4(state *[16]uint64, msg []byte) //go:noescape func updateAVX2(state *[16]uint64, msg []byte) //go:noescape func finalizeSSE4(out []byte, state *[16]uint64) //go:noescape func finalizeAVX2(out []byte, state *[16]uint64) func initialize(state *[16]uint64, key []byte) { switch { case useAVX2: initializeAVX2(state, key) case useSSE4: initializeSSE4(state, key) default: initializeGeneric(state, key) } } func update(state *[16]uint64, msg []byte) { switch { case useAVX2: updateAVX2(state, msg) case useSSE4: updateSSE4(state, msg) default: updateGeneric(state, msg) } } func finalize(out []byte, state *[16]uint64) { switch { case useAVX2: finalizeAVX2(out, state) case useSSE4: finalizeSSE4(out, state) default: finalizeGeneric(out, state) } } highwayhash-1.0.2/highwayhash_amd64.s000066400000000000000000000134421402712564500175130ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // +build amd64 !gccgo !appengine !nacl #include "textflag.h" DATA 路asmConstants<>+0x00(SB)/8, $0xdbe6d5d5fe4cce2f DATA 路asmConstants<>+0x08(SB)/8, $0xa4093822299f31d0 DATA 路asmConstants<>+0x10(SB)/8, $0x13198a2e03707344 DATA 路asmConstants<>+0x18(SB)/8, $0x243f6a8885a308d3 DATA 路asmConstants<>+0x20(SB)/8, $0x3bd39e10cb0ef593 DATA 路asmConstants<>+0x28(SB)/8, $0xc0acf169b5f18a8c DATA 路asmConstants<>+0x30(SB)/8, $0xbe5466cf34e90c6c DATA 路asmConstants<>+0x38(SB)/8, $0x452821e638d01377 GLOBL 路asmConstants<>(SB), (NOPTR+RODATA), $64 DATA 路asmZipperMerge<>+0x00(SB)/8, $0xf010e05020c03 DATA 路asmZipperMerge<>+0x08(SB)/8, $0x70806090d0a040b GLOBL 路asmZipperMerge<>(SB), (NOPTR+RODATA), $16 #define v00 X0 #define v01 X1 #define v10 X2 #define v11 X3 #define m00 X4 #define m01 X5 #define m10 X6 #define m11 X7 #define t0 X8 #define t1 X9 #define t2 X10 #define REDUCE_MOD(x0, x1, x2, x3, tmp0, tmp1, y0, y1) \ MOVQ $0x3FFFFFFFFFFFFFFF, tmp0 \ ANDQ tmp0, x3 \ MOVQ x2, y0 \ MOVQ x3, y1 \ \ MOVQ x2, tmp0 \ MOVQ x3, tmp1 \ SHLQ $1, tmp1 \ SHRQ $63, tmp0 \ MOVQ tmp1, x3 \ ORQ tmp0, x3 \ \ SHLQ $1, x2 \ \ MOVQ y0, tmp0 \ MOVQ y1, tmp1 \ SHLQ $2, tmp1 \ SHRQ $62, tmp0 \ MOVQ tmp1, y1 \ ORQ tmp0, y1 \ \ SHLQ $2, y0 \ \ XORQ x0, y0 \ XORQ x2, y0 \ XORQ x1, y1 \ XORQ x3, y1 #define UPDATE(msg0, msg1) \ PADDQ msg0, v10 \ PADDQ m00, v10 \ PADDQ msg1, v11 \ PADDQ m01, v11 \ \ MOVO v00, t0 \ MOVO v01, t1 \ PSRLQ $32, t0 \ PSRLQ $32, t1 \ PMULULQ v10, t0 \ PMULULQ v11, t1 \ PXOR t0, m00 \ PXOR t1, m01 \ \ PADDQ m10, v00 \ PADDQ m11, v01 \ \ MOVO v10, t0 \ MOVO v11, t1 \ PSRLQ $32, t0 \ PSRLQ $32, t1 \ PMULULQ v00, t0 \ PMULULQ v01, t1 \ PXOR t0, m10 \ PXOR t1, m11 \ \ MOVO v10, t0 \ PSHUFB t2, t0 \ MOVO v11, t1 \ PSHUFB t2, t1 \ PADDQ t0, v00 \ PADDQ t1, v01 \ \ MOVO v00, t0 \ PSHUFB t2, t0 \ MOVO v01, t1 \ PSHUFB t2, t1 \ PADDQ t0, v10 \ PADDQ t1, v11 // func initializeSSE4(state *[16]uint64, key []byte) TEXT 路initializeSSE4(SB), NOSPLIT, $0-32 MOVQ state+0(FP), AX MOVQ key_base+8(FP), BX MOVQ $路asmConstants<>(SB), CX MOVOU 0(BX), v00 MOVOU 16(BX), v01 PSHUFD $177, v00, v10 PSHUFD $177, v01, v11 MOVOU 0(CX), m00 MOVOU 16(CX), m01 MOVOU 32(CX), m10 MOVOU 48(CX), m11 PXOR m00, v00 PXOR m01, v01 PXOR m10, v10 PXOR m11, v11 MOVOU v00, 0(AX) MOVOU v01, 16(AX) MOVOU v10, 32(AX) MOVOU v11, 48(AX) MOVOU m00, 64(AX) MOVOU m01, 80(AX) MOVOU m10, 96(AX) MOVOU m11, 112(AX) RET // func updateSSE4(state *[16]uint64, msg []byte) TEXT 路updateSSE4(SB), NOSPLIT, $0-32 MOVQ state+0(FP), AX MOVQ msg_base+8(FP), BX MOVQ msg_len+16(FP), CX CMPQ CX, $32 JB DONE MOVOU 0(AX), v00 MOVOU 16(AX), v01 MOVOU 32(AX), v10 MOVOU 48(AX), v11 MOVOU 64(AX), m00 MOVOU 80(AX), m01 MOVOU 96(AX), m10 MOVOU 112(AX), m11 MOVOU 路asmZipperMerge<>(SB), t2 LOOP: MOVOU 0(BX), t0 MOVOU 16(BX), t1 UPDATE(t0, t1) ADDQ $32, BX SUBQ $32, CX JA LOOP MOVOU v00, 0(AX) MOVOU v01, 16(AX) MOVOU v10, 32(AX) MOVOU v11, 48(AX) MOVOU m00, 64(AX) MOVOU m01, 80(AX) MOVOU m10, 96(AX) MOVOU m11, 112(AX) DONE: RET // func finalizeSSE4(out []byte, state *[16]uint64) TEXT 路finalizeSSE4(SB), NOSPLIT, $0-32 MOVQ state+24(FP), AX MOVQ out_base+0(FP), BX MOVQ out_len+8(FP), CX MOVOU 0(AX), v00 MOVOU 16(AX), v01 MOVOU 32(AX), v10 MOVOU 48(AX), v11 MOVOU 64(AX), m00 MOVOU 80(AX), m01 MOVOU 96(AX), m10 MOVOU 112(AX), m11 MOVOU 路asmZipperMerge<>(SB), t2 PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) CMPQ CX, $8 JE skipUpdate // Just 4 rounds for 64-bit checksum PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) CMPQ CX, $16 JE skipUpdate // 6 rounds for 128-bit checksum PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) PSHUFD $177, v01, t0 PSHUFD $177, v00, t1 UPDATE(t0, t1) skipUpdate: MOVOU v00, 0(AX) MOVOU v01, 16(AX) MOVOU v10, 32(AX) MOVOU v11, 48(AX) MOVOU m00, 64(AX) MOVOU m01, 80(AX) MOVOU m10, 96(AX) MOVOU m11, 112(AX) CMPQ CX, $8 JE hash64 CMPQ CX, $16 JE hash128 // 256-bit checksum PADDQ v00, m00 PADDQ v10, m10 PADDQ v01, m01 PADDQ v11, m11 MOVQ m00, R8 PEXTRQ $1, m00, R9 MOVQ m10, R10 PEXTRQ $1, m10, R11 REDUCE_MOD(R8, R9, R10, R11, R12, R13, R14, R15) MOVQ R14, 0(BX) MOVQ R15, 8(BX) MOVQ m01, R8 PEXTRQ $1, m01, R9 MOVQ m11, R10 PEXTRQ $1, m11, R11 REDUCE_MOD(R8, R9, R10, R11, R12, R13, R14, R15) MOVQ R14, 16(BX) MOVQ R15, 24(BX) RET hash128: PADDQ v00, v11 PADDQ m00, m11 PADDQ v11, m11 MOVOU m11, 0(BX) RET hash64: PADDQ v00, v10 PADDQ m00, m10 PADDQ v10, m10 MOVQ m10, DX MOVQ DX, 0(BX) RET highwayhash-1.0.2/highwayhash_arm64.go000066400000000000000000000015511402712564500176720ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. //+build !noasm,!appengine package highwayhash var ( useSSE4 = false useAVX2 = false useNEON = true useVMX = false ) //go:noescape func initializeArm64(state *[16]uint64, key []byte) //go:noescape func updateArm64(state *[16]uint64, msg []byte) //go:noescape func finalizeArm64(out []byte, state *[16]uint64) func initialize(state *[16]uint64, key []byte) { if useNEON { initializeArm64(state, key) } else { initializeGeneric(state, key) } } func update(state *[16]uint64, msg []byte) { if useNEON { updateArm64(state, msg) } else { updateGeneric(state, msg) } } func finalize(out []byte, state *[16]uint64) { if useNEON { finalizeArm64(out, state) } else { finalizeGeneric(out, state) } } highwayhash-1.0.2/highwayhash_arm64.s000066400000000000000000000226311402712564500175310ustar00rootroot00000000000000// // Minio Cloud Storage, (C) 2017 Minio, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //+build !noasm,!appengine // Use github.com/minio/asm2plan9s on this file to assemble ARM instructions to // the opcodes of their Plan9 equivalents #include "textflag.h" #define REDUCE_MOD(x0, x1, x2, x3, tmp0, tmp1, y0, y1) \ MOVD $0x3FFFFFFFFFFFFFFF, tmp0 \ AND tmp0, x3 \ MOVD x2, y0 \ MOVD x3, y1 \ \ MOVD x2, tmp0 \ MOVD x3, tmp1 \ LSL $1, tmp1 \ LSR $63, tmp0 \ MOVD tmp1, x3 \ ORR tmp0, x3 \ \ LSL $1, x2 \ \ MOVD y0, tmp0 \ MOVD y1, tmp1 \ LSL $2, tmp1 \ LSR $62, tmp0 \ MOVD tmp1, y1 \ ORR tmp0, y1 \ \ LSL $2, y0 \ \ EOR x0, y0 \ EOR x2, y0 \ EOR x1, y1 \ EOR x3, y1 #define UPDATE(MSG1, MSG2) \ \ // Add message VADD MSG1.D2, V2.D2, V2.D2 \ VADD MSG2.D2, V3.D2, V3.D2 \ \ \ // v1 += mul0 VADD V4.D2, V2.D2, V2.D2 \ VADD V5.D2, V3.D2, V3.D2 \ \ \ // First pair of multiplies VTBL V29.B16, [V0.B16, V1.B16], V10.B16 \ VTBL V30.B16, [V2.B16, V3.B16], V11.B16 \ \ \ // VUMULL V10.S2, V11.S2, V12.D2 /* assembler support missing */ \ // VUMULL2 V10.S4, V11.S4, V13.D2 /* assembler support missing */ WORD $0x2eaac16c \ // umull v12.2d, v11.2s, v10.2s WORD $0x6eaac16d \ // umull2 v13.2d, v11.4s, v10.4s \ \ // v0 += mul1 VADD V6.D2, V0.D2, V0.D2 \ VADD V7.D2, V1.D2, V1.D2 \ \ \ // Second pair of multiplies VTBL V29.B16, [V2.B16, V3.B16], V15.B16 \ VTBL V30.B16, [V0.B16, V1.B16], V14.B16 \ \ \ // EOR multiplication result in VEOR V12.B16, V4.B16, V4.B16 \ VEOR V13.B16, V5.B16, V5.B16 \ \ \ // VUMULL V14.S2, V15.S2, V16.D2 /* assembler support missing */ \ // VUMULL2 V14.S4, V15.S4, V17.D2 /* assembler support missing */ WORD $0x2eaec1f0 \ // umull v16.2d, v15.2s, v14.2s WORD $0x6eaec1f1 \ // umull2 v17.2d, v15.4s, v14.4s \ \ // First pair of zipper-merges VTBL V28.B16, [V2.B16], V18.B16 \ VADD V18.D2, V0.D2, V0.D2 \ VTBL V28.B16, [V3.B16], V19.B16 \ VADD V19.D2, V1.D2, V1.D2 \ \ \ // Second pair of zipper-merges VTBL V28.B16, [V0.B16], V20.B16 \ VADD V20.D2, V2.D2, V2.D2 \ VTBL V28.B16, [V1.B16], V21.B16 \ VADD V21.D2, V3.D2, V3.D2 \ \ \ // EOR multiplication result in VEOR V16.B16, V6.B16, V6.B16 \ VEOR V17.B16, V7.B16, V7.B16 // func initializeArm64(state *[16]uint64, key []byte) TEXT 路initializeArm64(SB), NOSPLIT, $0 MOVD state+0(FP), R0 MOVD key_base+8(FP), R1 VLD1 (R1), [V1.S4, V2.S4] VREV64 V1.S4, V3.S4 VREV64 V2.S4, V4.S4 MOVD $路asmConstants(SB), R3 VLD1 (R3), [V5.S4, V6.S4, V7.S4, V8.S4] VEOR V5.B16, V1.B16, V1.B16 VEOR V6.B16, V2.B16, V2.B16 VEOR V7.B16, V3.B16, V3.B16 VEOR V8.B16, V4.B16, V4.B16 VST1.P [V1.D2, V2.D2, V3.D2, V4.D2], 64(R0) VST1 [V5.D2, V6.D2, V7.D2, V8.D2], (R0) RET TEXT 路updateArm64(SB), NOSPLIT, $0 MOVD state+0(FP), R0 MOVD msg_base+8(FP), R1 MOVD msg_len+16(FP), R2 // length of message SUBS $32, R2 BMI complete // Definition of registers // v0 = v0.lo // v1 = v0.hi // v2 = v1.lo // v3 = v1.hi // v4 = mul0.lo // v5 = mul0.hi // v6 = mul1.lo // v7 = mul1.hi // Load zipper merge constants table pointer MOVD $路asmZipperMerge(SB), R3 // and load zipper merge constants into v28, v29, and v30 VLD1 (R3), [V28.B16, V29.B16, V30.B16] VLD1.P 64(R0), [V0.D2, V1.D2, V2.D2, V3.D2] VLD1 (R0), [V4.D2, V5.D2, V6.D2, V7.D2] SUBS $64, R0 loop: // Main loop VLD1.P 32(R1), [V26.S4, V27.S4] UPDATE(V26, V27) SUBS $32, R2 BPL loop // Store result VST1.P [V0.D2, V1.D2, V2.D2, V3.D2], 64(R0) VST1 [V4.D2, V5.D2, V6.D2, V7.D2], (R0) complete: RET // func finalizeArm64(out []byte, state *[16]uint64) TEXT 路finalizeArm64(SB), NOSPLIT, $0-32 MOVD state+24(FP), R0 MOVD out_base+0(FP), R1 MOVD out_len+8(FP), R2 // Load zipper merge constants table pointer MOVD $路asmZipperMerge(SB), R3 // and load zipper merge constants into v28, v29, and v30 VLD1 (R3), [V28.B16, V29.B16, V30.B16] VLD1.P 64(R0), [V0.D2, V1.D2, V2.D2, V3.D2] VLD1 (R0), [V4.D2, V5.D2, V6.D2, V7.D2] SUB $64, R0 VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) CMP $8, R2 BEQ skipUpdate // Just 4 rounds for 64-bit checksum VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) CMP $16, R2 BEQ skipUpdate // 6 rounds for 128-bit checksum VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) VREV64 V1.S4, V26.S4 VREV64 V0.S4, V27.S4 UPDATE(V26, V27) skipUpdate: // Store result VST1.P [V0.D2, V1.D2, V2.D2, V3.D2], 64(R0) VST1 [V4.D2, V5.D2, V6.D2, V7.D2], (R0) SUB $64, R0 CMP $8, R2 BEQ hash64 CMP $16, R2 BEQ hash128 // 256-bit checksum MOVD 0*8(R0), R8 MOVD 1*8(R0), R9 MOVD 4*8(R0), R10 MOVD 5*8(R0), R11 MOVD 8*8(R0), R4 MOVD 9*8(R0), R5 MOVD 12*8(R0), R6 MOVD 13*8(R0), R7 ADD R4, R8 ADD R5, R9 ADD R6, R10 ADD R7, R11 REDUCE_MOD(R8, R9, R10, R11, R4, R5, R6, R7) MOVD R6, 0(R1) MOVD R7, 8(R1) MOVD 2*8(R0), R8 MOVD 3*8(R0), R9 MOVD 6*8(R0), R10 MOVD 7*8(R0), R11 MOVD 10*8(R0), R4 MOVD 11*8(R0), R5 MOVD 14*8(R0), R6 MOVD 15*8(R0), R7 ADD R4, R8 ADD R5, R9 ADD R6, R10 ADD R7, R11 REDUCE_MOD(R8, R9, R10, R11, R4, R5, R6, R7) MOVD R6, 16(R1) MOVD R7, 24(R1) RET hash128: MOVD 0*8(R0), R8 MOVD 1*8(R0), R9 MOVD 6*8(R0), R10 MOVD 7*8(R0), R11 ADD R10, R8 ADD R11, R9 MOVD 8*8(R0), R10 MOVD 9*8(R0), R11 ADD R10, R8 ADD R11, R9 MOVD 14*8(R0), R10 MOVD 15*8(R0), R11 ADD R10, R8 ADD R11, R9 MOVD R8, 0(R1) MOVD R9, 8(R1) RET hash64: MOVD 0*8(R0), R4 MOVD 4*8(R0), R5 MOVD 8*8(R0), R6 MOVD 12*8(R0), R7 ADD R5, R4 ADD R7, R6 ADD R6, R4 MOVD R4, (R1) RET DATA 路asmConstants+0x00(SB)/8, $0xdbe6d5d5fe4cce2f DATA 路asmConstants+0x08(SB)/8, $0xa4093822299f31d0 DATA 路asmConstants+0x10(SB)/8, $0x13198a2e03707344 DATA 路asmConstants+0x18(SB)/8, $0x243f6a8885a308d3 DATA 路asmConstants+0x20(SB)/8, $0x3bd39e10cb0ef593 DATA 路asmConstants+0x28(SB)/8, $0xc0acf169b5f18a8c DATA 路asmConstants+0x30(SB)/8, $0xbe5466cf34e90c6c DATA 路asmConstants+0x38(SB)/8, $0x452821e638d01377 GLOBL 路asmConstants(SB), 8, $64 // Constants for TBL instructions DATA 路asmZipperMerge+0x0(SB)/8, $0x000f010e05020c03 // zipper merge constant DATA 路asmZipperMerge+0x8(SB)/8, $0x070806090d0a040b DATA 路asmZipperMerge+0x10(SB)/8, $0x0f0e0d0c07060504 // setup first register for multiply DATA 路asmZipperMerge+0x18(SB)/8, $0x1f1e1d1c17161514 DATA 路asmZipperMerge+0x20(SB)/8, $0x0b0a090803020100 // setup second register for multiply DATA 路asmZipperMerge+0x28(SB)/8, $0x1b1a191813121110 GLOBL 路asmZipperMerge(SB), 8, $48 highwayhash-1.0.2/highwayhash_generic.go000066400000000000000000000113051402712564500203530ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. package highwayhash import ( "encoding/binary" ) const ( v0 = 0 v1 = 4 mul0 = 8 mul1 = 12 ) var ( init0 = [4]uint64{0xdbe6d5d5fe4cce2f, 0xa4093822299f31d0, 0x13198a2e03707344, 0x243f6a8885a308d3} init1 = [4]uint64{0x3bd39e10cb0ef593, 0xc0acf169b5f18a8c, 0xbe5466cf34e90c6c, 0x452821e638d01377} ) func initializeGeneric(state *[16]uint64, k []byte) { var key [4]uint64 key[0] = binary.LittleEndian.Uint64(k[0:]) key[1] = binary.LittleEndian.Uint64(k[8:]) key[2] = binary.LittleEndian.Uint64(k[16:]) key[3] = binary.LittleEndian.Uint64(k[24:]) copy(state[mul0:], init0[:]) copy(state[mul1:], init1[:]) for i, k := range key { state[v0+i] = init0[i] ^ k } key[0] = key[0]>>32 | key[0]<<32 key[1] = key[1]>>32 | key[1]<<32 key[2] = key[2]>>32 | key[2]<<32 key[3] = key[3]>>32 | key[3]<<32 for i, k := range key { state[v1+i] = init1[i] ^ k } } func updateGeneric(state *[16]uint64, msg []byte) { for len(msg) > 0 { // add message state[v1+0] += binary.LittleEndian.Uint64(msg) state[v1+1] += binary.LittleEndian.Uint64(msg[8:]) state[v1+2] += binary.LittleEndian.Uint64(msg[16:]) state[v1+3] += binary.LittleEndian.Uint64(msg[24:]) // v1 += mul0 state[v1+0] += state[mul0+0] state[v1+1] += state[mul0+1] state[v1+2] += state[mul0+2] state[v1+3] += state[mul0+3] state[mul0+0] ^= uint64(uint32(state[v1+0])) * (state[v0+0] >> 32) state[mul0+1] ^= uint64(uint32(state[v1+1])) * (state[v0+1] >> 32) state[mul0+2] ^= uint64(uint32(state[v1+2])) * (state[v0+2] >> 32) state[mul0+3] ^= uint64(uint32(state[v1+3])) * (state[v0+3] >> 32) // v0 += mul1 state[v0+0] += state[mul1+0] state[v0+1] += state[mul1+1] state[v0+2] += state[mul1+2] state[v0+3] += state[mul1+3] state[mul1+0] ^= uint64(uint32(state[v0+0])) * (state[v1+0] >> 32) state[mul1+1] ^= uint64(uint32(state[v0+1])) * (state[v1+1] >> 32) state[mul1+2] ^= uint64(uint32(state[v0+2])) * (state[v1+2] >> 32) state[mul1+3] ^= uint64(uint32(state[v0+3])) * (state[v1+3] >> 32) zipperMerge(state[v1+0], state[v1+1], &state[v0+0], &state[v0+1]) zipperMerge(state[v1+2], state[v1+3], &state[v0+2], &state[v0+3]) zipperMerge(state[v0+0], state[v0+1], &state[v1+0], &state[v1+1]) zipperMerge(state[v0+2], state[v0+3], &state[v1+2], &state[v1+3]) msg = msg[32:] } } func finalizeGeneric(out []byte, state *[16]uint64) { var perm [4]uint64 var tmp [32]byte runs := 4 if len(out) == 16 { runs = 6 } else if len(out) == 32 { runs = 10 } for i := 0; i < runs; i++ { perm[0] = state[v0+2]>>32 | state[v0+2]<<32 perm[1] = state[v0+3]>>32 | state[v0+3]<<32 perm[2] = state[v0+0]>>32 | state[v0+0]<<32 perm[3] = state[v0+1]>>32 | state[v0+1]<<32 binary.LittleEndian.PutUint64(tmp[0:], perm[0]) binary.LittleEndian.PutUint64(tmp[8:], perm[1]) binary.LittleEndian.PutUint64(tmp[16:], perm[2]) binary.LittleEndian.PutUint64(tmp[24:], perm[3]) update(state, tmp[:]) } switch len(out) { case 8: binary.LittleEndian.PutUint64(out, state[v0+0]+state[v1+0]+state[mul0+0]+state[mul1+0]) case 16: binary.LittleEndian.PutUint64(out, state[v0+0]+state[v1+2]+state[mul0+0]+state[mul1+2]) binary.LittleEndian.PutUint64(out[8:], state[v0+1]+state[v1+3]+state[mul0+1]+state[mul1+3]) case 32: h0, h1 := reduceMod(state[v0+0]+state[mul0+0], state[v0+1]+state[mul0+1], state[v1+0]+state[mul1+0], state[v1+1]+state[mul1+1]) binary.LittleEndian.PutUint64(out[0:], h0) binary.LittleEndian.PutUint64(out[8:], h1) h0, h1 = reduceMod(state[v0+2]+state[mul0+2], state[v0+3]+state[mul0+3], state[v1+2]+state[mul1+2], state[v1+3]+state[mul1+3]) binary.LittleEndian.PutUint64(out[16:], h0) binary.LittleEndian.PutUint64(out[24:], h1) } } func zipperMerge(v0, v1 uint64, d0, d1 *uint64) { m0 := v0 & (0xFF << (2 * 8)) m1 := (v1 & (0xFF << (7 * 8))) >> 8 m2 := ((v0 & (0xFF << (5 * 8))) + (v1 & (0xFF << (6 * 8)))) >> 16 m3 := ((v0 & (0xFF << (3 * 8))) + (v1 & (0xFF << (4 * 8)))) >> 24 m4 := (v0 & (0xFF << (1 * 8))) << 32 m5 := v0 << 56 *d0 += m0 + m1 + m2 + m3 + m4 + m5 m0 = (v0 & (0xFF << (7 * 8))) + (v1 & (0xFF << (2 * 8))) m1 = (v0 & (0xFF << (6 * 8))) >> 8 m2 = (v1 & (0xFF << (5 * 8))) >> 16 m3 = ((v1 & (0xFF << (3 * 8))) + (v0 & (0xFF << (4 * 8)))) >> 24 m4 = (v1 & 0xFF) << 48 m5 = (v1 & (0xFF << (1 * 8))) << 24 *d1 += m3 + m2 + m5 + m1 + m4 + m0 } // reduce v = [v0, v1, v2, v3] mod the irreducible polynomial x^128 + x^2 + x func reduceMod(v0, v1, v2, v3 uint64) (r0, r1 uint64) { v3 &= 0x3FFFFFFFFFFFFFFF r0, r1 = v2, v3 v3 = (v3 << 1) | (v2 >> (64 - 1)) v2 <<= 1 r1 = (r1 << 2) | (r0 >> (64 - 2)) r0 <<= 2 r0 ^= v0 ^ v2 r1 ^= v1 ^ v3 return } highwayhash-1.0.2/highwayhash_ppc64le.go000066400000000000000000000011661402712564500202200ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. //+build !noasm,!appengine package highwayhash var ( useSSE4 = false useAVX2 = false useNEON = false useVMX = true ) //go:noescape func updatePpc64Le(state *[16]uint64, msg []byte) func initialize(state *[16]uint64, key []byte) { initializeGeneric(state, key) } func update(state *[16]uint64, msg []byte) { if useVMX { updatePpc64Le(state, msg) } else { updateGeneric(state, msg) } } func finalize(out []byte, state *[16]uint64) { finalizeGeneric(out, state) } highwayhash-1.0.2/highwayhash_ppc64le.s000066400000000000000000000113201402712564500200460ustar00rootroot00000000000000// // Minio Cloud Storage, (C) 2018 Minio, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //+build !noasm,!appengine #include "textflag.h" // Definition of registers #define V0_LO VS32 #define V0_LO_ V0 #define V0_HI VS33 #define V0_HI_ V1 #define V1_LO VS34 #define V1_LO_ V2 #define V1_HI VS35 #define V1_HI_ V3 #define MUL0_LO VS36 #define MUL0_LO_ V4 #define MUL0_HI VS37 #define MUL0_HI_ V5 #define MUL1_LO VS38 #define MUL1_LO_ V6 #define MUL1_HI VS39 #define MUL1_HI_ V7 // Message #define MSG_LO VS40 #define MSG_LO_ V8 #define MSG_HI VS41 // Constants #define ROTATE VS42 #define ROTATE_ V10 #define MASK VS43 #define MASK_ V11 // Temps #define TEMP1 VS44 #define TEMP1_ V12 #define TEMP2 VS45 #define TEMP2_ V13 #define TEMP3 VS46 #define TEMP3_ V14 #define TEMP4_ V15 #define TEMP5_ V16 #define TEMP6_ V17 #define TEMP7_ V18 // Regular registers #define STATE R3 #define MSG_BASE R4 #define MSG_LEN R5 #define CONSTANTS R6 #define P1 R7 #define P2 R8 #define P3 R9 #define P4 R10 #define P5 R11 #define P6 R12 #define P7 R14 // avoid using R13 TEXT 路updatePpc64Le(SB), NOFRAME|NOSPLIT, $0-32 MOVD state+0(FP), STATE MOVD msg_base+8(FP), MSG_BASE MOVD msg_len+16(FP), MSG_LEN // length of message // Sanity check for length CMPU MSG_LEN, $31 BLE complete // Setup offsets MOVD $16, P1 MOVD $32, P2 MOVD $48, P3 MOVD $64, P4 MOVD $80, P5 MOVD $96, P6 MOVD $112, P7 // Load state LXVD2X (STATE)(R0), V0_LO LXVD2X (STATE)(P1), V0_HI LXVD2X (STATE)(P2), V1_LO LXVD2X (STATE)(P3), V1_HI LXVD2X (STATE)(P4), MUL0_LO LXVD2X (STATE)(P5), MUL0_HI LXVD2X (STATE)(P6), MUL1_LO LXVD2X (STATE)(P7), MUL1_HI XXPERMDI V0_LO, V0_LO, $2, V0_LO XXPERMDI V0_HI, V0_HI, $2, V0_HI XXPERMDI V1_LO, V1_LO, $2, V1_LO XXPERMDI V1_HI, V1_HI, $2, V1_HI XXPERMDI MUL0_LO, MUL0_LO, $2, MUL0_LO XXPERMDI MUL0_HI, MUL0_HI, $2, MUL0_HI XXPERMDI MUL1_LO, MUL1_LO, $2, MUL1_LO XXPERMDI MUL1_HI, MUL1_HI, $2, MUL1_HI // Load asmConstants table pointer MOVD $路asmConstants(SB), CONSTANTS LXVD2X (CONSTANTS)(R0), ROTATE LXVD2X (CONSTANTS)(P1), MASK XXLNAND MASK, MASK, MASK loop: // Main highwayhash update loop LXVD2X (MSG_BASE)(R0), MSG_LO VADDUDM V0_LO_, MUL1_LO_, TEMP1_ VRLD V0_LO_, ROTATE_, TEMP2_ VADDUDM MUL1_HI_, V0_HI_, TEMP3_ LXVD2X (MSG_BASE)(P1), MSG_HI ADD $32, MSG_BASE, MSG_BASE XXPERMDI MSG_LO, MSG_LO, $2, MSG_LO XXPERMDI MSG_HI, MSG_HI, $2, V0_LO VADDUDM MSG_LO_, MUL0_LO_, MSG_LO_ VADDUDM V0_LO_, MUL0_HI_, V0_LO_ VADDUDM MSG_LO_, V1_LO_, V1_LO_ VSRD V0_HI_, ROTATE_, MSG_LO_ VADDUDM V0_LO_, V1_HI_, V1_HI_ VPERM V1_LO_, V1_LO_, MASK_, V0_LO_ VMULOUW V1_LO_, TEMP2_, TEMP2_ VPERM V1_HI_, V1_HI_, MASK_, TEMP7_ VADDUDM V0_LO_, TEMP1_, V0_LO_ VMULOUW V1_HI_, MSG_LO_, MSG_LO_ VADDUDM TEMP7_, TEMP3_, V0_HI_ VPERM V0_LO_, V0_LO_, MASK_, TEMP6_ VRLD V1_LO_, ROTATE_, TEMP4_ VSRD V1_HI_, ROTATE_, TEMP5_ VPERM V0_HI_, V0_HI_, MASK_, TEMP7_ XXLXOR MUL0_LO, TEMP2, MUL0_LO VMULOUW TEMP1_, TEMP4_, TEMP1_ VMULOUW TEMP3_, TEMP5_, TEMP3_ XXLXOR MUL0_HI, MSG_LO, MUL0_HI XXLXOR MUL1_LO, TEMP1, MUL1_LO XXLXOR MUL1_HI, TEMP3, MUL1_HI VADDUDM TEMP6_, V1_LO_, V1_LO_ VADDUDM TEMP7_, V1_HI_, V1_HI_ SUB $32, MSG_LEN, MSG_LEN CMPU MSG_LEN, $32 BGE loop // Save state XXPERMDI V0_LO, V0_LO, $2, V0_LO XXPERMDI V0_HI, V0_HI, $2, V0_HI XXPERMDI V1_LO, V1_LO, $2, V1_LO XXPERMDI V1_HI, V1_HI, $2, V1_HI XXPERMDI MUL0_LO, MUL0_LO, $2, MUL0_LO XXPERMDI MUL0_HI, MUL0_HI, $2, MUL0_HI XXPERMDI MUL1_LO, MUL1_LO, $2, MUL1_LO XXPERMDI MUL1_HI, MUL1_HI, $2, MUL1_HI STXVD2X V0_LO, (STATE)(R0) STXVD2X V0_HI, (STATE)(P1) STXVD2X V1_LO, (STATE)(P2) STXVD2X V1_HI, (STATE)(P3) STXVD2X MUL0_LO, (STATE)(P4) STXVD2X MUL0_HI, (STATE)(P5) STXVD2X MUL1_LO, (STATE)(P6) STXVD2X MUL1_HI, (STATE)(P7) complete: RET // Constants table DATA 路asmConstants+0x0(SB)/8, $0x0000000000000020 DATA 路asmConstants+0x8(SB)/8, $0x0000000000000020 DATA 路asmConstants+0x10(SB)/8, $0x070806090d0a040b // zipper merge constant DATA 路asmConstants+0x18(SB)/8, $0x000f010e05020c03 // zipper merge constant GLOBL 路asmConstants(SB), 8, $32 highwayhash-1.0.2/highwayhash_ref.go000066400000000000000000000010071402712564500175110ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // +build noasm !amd64,!arm64,!ppc64le package highwayhash var ( useSSE4 = false useAVX2 = false useNEON = false useVMX = false ) func initialize(state *[16]uint64, k []byte) { initializeGeneric(state, k) } func update(state *[16]uint64, msg []byte) { updateGeneric(state, msg) } func finalize(out []byte, state *[16]uint64) { finalizeGeneric(out, state) } highwayhash-1.0.2/highwayhash_test.go000066400000000000000000000335231402712564500177240ustar00rootroot00000000000000// Copyright (c) 2017 Minio Inc. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. package highwayhash import ( "bytes" "encoding/binary" "encoding/hex" "hash" "math/rand" "runtime" "sync/atomic" "testing" ) func TestVectors(t *testing.T) { defer func(sse4, avx2, neon, vmx bool) { useSSE4, useAVX2, useNEON, useVMX = sse4, avx2, neon, vmx }(useSSE4, useAVX2, useNEON, useVMX) if useAVX2 { t.Run("AVX2 version", func(t *testing.T) { testVectors(func(key []byte) (hash.Hash, error) { return New64(key) }, testVectors64, t) testVectors(New128, testVectors128, t) testVectors(New, testVectors256, t) useAVX2 = false }) } if useSSE4 { t.Run("SSE4 version", func(t *testing.T) { testVectors(func(key []byte) (hash.Hash, error) { return New64(key) }, testVectors64, t) testVectors(New128, testVectors128, t) testVectors(New, testVectors256, t) useSSE4 = false }) } if useNEON { t.Run("NEON version", func(t *testing.T) { testVectors(func(key []byte) (hash.Hash, error) { return New64(key) }, testVectors64, t) testVectors(New128, testVectors128, t) testVectors(New, testVectors256, t) useNEON = false }) } if useVMX { t.Run("VMX version", func(t *testing.T) { testVectors(func(key []byte) (hash.Hash, error) { return New64(key) }, testVectors64, t) testVectors(New128, testVectors128, t) testVectors(New, testVectors256, t) useVMX = false }) } t.Run("Generic version", func(t *testing.T) { testVectors(func(key []byte) (hash.Hash, error) { return New64(key) }, testVectors64, t) testVectors(New128, testVectors128, t) testVectors(New, testVectors256, t) }) } func testVectors(NewFunc func([]byte) (hash.Hash, error), vectors []string, t *testing.T) { key, err := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f") if err != nil { t.Fatalf("Failed to decode key: %v", err) } input := make([]byte, len(vectors)) h, err := NewFunc(key[:]) if err != nil { t.Fatalf("Failed to create highwayhash instance: %v", err) } for i, v := range vectors { input[i] = byte(i) expected, err := hex.DecodeString(v) if err != nil { t.Fatalf("Failed to decode test vector: %v error: %v", v, err) } h.Write(input[:i]) if sum := h.Sum(nil); !bytes.Equal(sum, expected[:]) { t.Errorf("Test %d: hash mismatch: got: %v want: %v", i, hex.EncodeToString(sum), hex.EncodeToString(expected)) } h.Reset() switch h.Size() { case Size: if sum := Sum(input[:i], key); !bytes.Equal(sum[:], expected) { t.Errorf("Test %d: Sum mismatch: got: %v want: %v", i, hex.EncodeToString(sum[:]), hex.EncodeToString(expected)) } case Size128: if sum := Sum128(input[:i], key); !bytes.Equal(sum[:], expected) { t.Errorf("Test %d: Sum mismatch: got: %v want: %v", i, hex.EncodeToString(sum[:]), hex.EncodeToString(expected)) } case Size64: var sum [Size64]byte binary.LittleEndian.PutUint64(sum[:], Sum64(input[:i], key)) if !bytes.Equal(sum[:], expected) { t.Errorf("Test %d: Sum mismatch: got: %v want: %v", i, hex.EncodeToString(sum[:]), hex.EncodeToString(expected)) } } } } // HighwayHash is frozen, so the golden values will not change. var testVectors64 = []string{ "536ec222de567a90", "78ddcdc7aa43ab7e", "623db5b09a56d0b8", "803d468aabef6b5c", "da7e009368a405f2", "4145a9e468168a2b", "6fcaef5b32cc4cbd", "8294f53817ae024d", "71315fe5085120e1", "84157ac74e64d232", "0ba903b1cd0ae1f6", "155c415b61f4bbc3", "9cfa630004c23c24", "ff41e665ce589aa8", "235a4548a331b024", "3bf349a4863f7940", "32b87ef98934abcf", "e2c0c5c8d267fe19", "c25c569ca690dd04", "04c571238e51d975", "16ddd341119bad38", "e0708acd2c436402", "90336888625adba9", "8c023f009254b0d7", "1ee559ea5a615f20", "8428052196c8e0ee", "4f4f28a7931afc1b", "1da90db7b5752151", "39c6a2a076891ff7", "e7e3841fef3f09ae", "0f866111b092ca22", "685a03cf7c00c79f", "fc80d5ecd964c9a0", "fc8131a03cf7902c", "9eeb91564ef85c18", "9baa5227eff5c14f", "eb330a5e1a39b7f5", "9c6ce9b4834bb8b9", "b4d95c2a71fe425e", "dc973f0cf9f250a1", "7d632d5ed722a57f", "2bd3ff0dccd01a18", "2840851e98ed8938", "2dee86c5e89742fb", "9c0528bb454a066d", "0c86ecb309365690", "66c69740e9fca47a", "081e916bc0ba2613", "344f152b8d1626b9", "8d94b14589841999", "be5e8234c58fa9a2", "b6f03e21959080e9", "e9c07b7083542e58", "f56a8aa814946e08", "3d74f6208db986ee", "a7c0b109f67f9bf8", "e8c3229ec19c7d4c", "6f2a56245000979a", "efebe623f41cd45d", "27e268049c6013df", "5a158841f6a40d6e", "a1d4d7504bba55b7", "bd79746484347a88", "a03921bfe9eb8eab", "ffa6d24c5d2c5475", } var testVectors128 = []string{ "c7fe8f9d8f26ed0f6f3e097f765e5633", "a8e7813689a8b0d6b4dc9cebf91d29dc", "04da165a26ad153d68e832dc38560878", "eb0b5f291b62070679ddced90f9ae6bf", "9ee4ac6db49e392608923139d02a922e", "d82ed186c3bd50323ac2636c90103819", "476589cbb36a476f1910ed376f57de7c", "b4717169ca1f402a6c79029fff031fbe", "e8520528846de9a1c20aec3bc6f15c69", "b2631ef302212a14cc00505b8cb9851a", "5bbcb6260eb7a1515955a42d3b1f9e92", "5b419a0562039988137d7bc4221fd2be", "6695af1c5f1f1fcdd4c8f9e08cba18a8", "5761fe12415625a248b8ddb8784ce9b2", "1909ccd1eb2f49bda2415602bc1dcdce", "54afc42ba5372214d7bc266e0b6c79e0", "ad01a4d5ff604441c8189f01d5a39e02", "62991cc5964b2ac5a05e9b16b178b8ec", "ceeafb118fca40d931d5f816d6463af9", "f5cbc0e50a9dc48a937c1df58dbffd3f", "a8002d859b276dac46aaeba56b3acd7d", "568af093bd2116f1d5d93d1698c37331", "9ff88cf650e24c0ced981841da3c12b3", "ce519a3ded97ab150e0869914774e27c", "b845488d191e00cd772daad88bd9d9d0", "793d49a017d6f334167e7f39f604d37d", "b6c6f4a99068b55c4f30676516290813", "c0d15b248b6fda308c74d93f7e8b826f", "c0124c20490358e01c445fac0cdaf693", "453007a51b7348f67659b64f1197b85f", "06528a7354834f0291097eeb18499a50", "297ca5e865b4e70646d4f5073a5e4152", "aa4a43c166df8419b9e4b3f95819fc16", "6cc3c6e0af7816119d84a2e59db558f9", "9004fb4084bc3f7736856543d2d56ec9", "41c9b60b71dce391e9aceec10b6a33ea", "d4d97a5d81e3cf259ec58f828c4fe9f2", "f288c23cb838fbb904ec50f8c8c47974", "8c2b9825c5d5851df4db486fc1b1266e", "e7bd6060bd554e8ad03f8b0599d53421", "368f7794f98f952a23641de61a2d05e8", "333245bee63a2389b9c0e8d7879ccf3a", "d5c8a97ee2f5584440512aca9bb48f41", "682ad17e83010309e661c83396f61710", "9095d40447d80d33e4a64b3aadf19d33", "76c5f263a6639356f65ec9e3953d3b36", "3707b98685d0c8ace9284e7d08e8a02b", "20956dc8277ac2392e936051a420b68d", "2d071a67eb4a6a8ee67ee4101a56d36e", "4ac7beb165d711002e84de6e656e0ed8", "4cc66a932bd615257d8a08d7948708ce", "af236ec152156291efcc23eb94004f26", "803426970d88211e8610a3d3074865d8", "2d437f09af6ad7393947079de0e117a5", "145ac637f3a4170fd476f9695f21512f", "445e8912da5cfba0d13cf1d1c43d8c56", "ce469cd800fcc893690e337e94dad5ba", "94561a1d50077c812bacbf2ce76e4d58", "bf53f073af68d691ede0c18376648ef9", "8bcf3c6befe18152d8836016dfc34cbc", "b9eeaabe6d1bd6aa7b78160c009d96ff", "795847c04fd825432d1c5f90bd19b914", "d1a66baad176a179862b3aa5c520f7f1", "f03e2f021870bd74cb4b5fada894ea3a", "f2c4d498711fbb98c88f91de7105bce0", } var testVectors256 = []string{ "f574c8c22a4844dd1f35c713730146d9ff1487b9ccbeaeb3f41d75453123da41", "54825fe4bc41b9ed0fc6ca3def440de2474a32cb9b1b657284e475b24c627320", "54e4af24dff9df3f73e80a1b1abfc4117a592269cc6951112cb4330d59f60812", "5cd9d10dd7a00a48d0d111697c5e22895a86bb8b6b42a88e22c7e190c3fb3de2", "dce42b2197c4cfc99b92d2aff69d5fa89e10f41d219fda1f9b4f4d377a27e407", "b385dca466f5b4b44201465eba634bbfe31ddccd688ef415c68580387d58740f", "b4b9ad860ac74564b6ceb48427fb9ca913dbb2a0409de2da70119d9af26d52b6", "81ad8709a0b166d6376d8ceb38f8f1a430e063d4076e22e96c522c067dd65457", "c08b76edb005b9f1453afffcf36f97e67897d0d98d51be4f330d1e37ebafa0d9", "81293c0dd7e4d880a1f12464d1bb0ff1d10c3f9dbe2d5ccff273b601f7e8bfc0", "be62a2e5508ce4ade038fefdb192948e38b8e92f4bb78407cd6d65db74d5410e", "cf071853b977bea138971a6adea797ba1f268e9cef4c27afe8e84cc735b9393e", "575840e30238ad15a053e839dccb119d25b2313c993eea232e21f4cae3e9d96c", "367cd7b15e6fc901a6951f53c1f967a3b8dcda7c42a3941fd3d53bbf0a00f197", "418effee1ee915085ddf216efa280c0e745309ed628ead4ee6739d1cda01fd3f", "2e604278700519c146b1018501dbc362c10634fa17adf58547c3fed47bf884c8", "1fcdb6a189d91af5d97b622ad675f0f7068af279f5d5017e9f4d176ac115d41a", "8e06a42ca8cff419b975923abd4a9d3bc610c0e9ddb000801356214909d58488", "5d9fab817f6c6d12ee167709c5a3da4e493edda7731512af2dc380aa85ac0190", "fa559114f9beaa063d1ce744414f86dfda64bc60e8bcbafdb61c499247a52bde", "db9f0735406bfcad656e488e32b787a0ea23465a93a9d14644ee3c0d445c89e3", "dfb3a3ee1dd3f9b533e1060ae224308f20e18f28c8384cf24997d69bcf1d3f70", "e3ef9447850b3c2ba0ceda9b963f5d1c2eac63a5af6af1817530d0795a1c4423", "6237fd93c7f88a4124f9d761948e6bbc789e1a2a6af26f776eca17d4bfb7a03a", "c1a355d22aea03cd2a1b9cb5e5fe8501e473974fd438f4d1e4763bf867dd69be", "fba0873887a851f9aee048a5d2317b2cfa6e18b638388044729f21bec78ec7a3", "088c0dea51f18f958834f6b497897e4b6d38c55143078ec7faee206f557755d9", "0654b07f8017a9298c571f3584f81833faa7f6f66eea24ddffae975e469343e7", "cb6c5e9380082498da979fb071d2d01f83b100274786e7561778749ff9491629", "56c554704f95d41beb6c597cff2edbff5b6bab1b9ac66a7c53c17f537076030f", "9874599788e32588c13263afebf67c6417c928dc03d92b55abc5bf002c63d772", "4d641a6076e28068dab70fb1208b72b36ed110060612bdd0f22e4533ef14ef8a", "fec3a139908ce3bc8912c1a32663d542a9aefc64f79555e3995a47c96b3cb0c9", "e5a634f0cb1501f6d046cebf75ea366c90597282d3c8173b357a0011eda2da7e", "a2def9ed59e926130c729f73016877c42ff662d70f506951ab29250ad9d00d8a", "d442d403d549519344d1da0213b46bffec369dcd12b09c333022cc9e61531de6", "96b650aa88c88b52fce18460a3ecaeb8763424c01e1558a144ec7c09ad4ac102", "27c31722a788d6be3f8760f71451e61ea602307db3265c3fb997156395e8f2dd", "ad510b2bcf21dbe76cabb0f42463fcfa5b9c2dc2447285b09c84051e8d88adf0", "00cb4dcd93975105eb7d0663314a593c349e11cf1a0875ac94b05c809762c85a", "9e77b5228c8d2209847e6b51b24d6419a04131f8abc8922b9193e125d75a787f", "4ba7d0465d2ec459646003ca653ca55eb4ae35b66b91a948d4e9543f14dfe6ba", "e3d0036d6923b65e92a01db4bc783dd50db1f652dc4823fe118c2c6357248064", "8154b8c4b21bb643a1807e71258c31c67d689c6f4d7f4a8c7c1d4035e01702bd", "374c824357ca517f3a701db15e4d4cb069f3f6cb1e1e514de2565421ea7567d6", "cc457ef8ee09b439b379fc59c4e8b852248c85d1180992444901ee5e647bf080", "14d59abed19486cee73668522690a1bf7d2a90e4f6fda41efee196d658440c38", "a4a023f88be189d1d7a701e53b353b1f84282ee0b4774fa20c18f9746f64947e", "48ec25d335c6f8af0b8d0314a40a2e2c6774441a617fd34e8914503be338ec39", "97f1835fadfd2b2acc74f2be6e3e3d0155617277043c56e17e0332e95d8a5af1", "326312c81ef9d1d511ffb1f99b0b111032601c5426ab75a15215702857dcba87", "842808d82ca9b5c7fbee2e1bb62aa6dd2f73aefeec82988ffb4f1fc05cbd386b", "f0323d7375f26ecf8b7dbfa22d82f0a36a4012f535744e302d17b3ebefe3280b", "dbe9b20107f898e628888a9a812aae66c9f2b8c92490ea14a4b53e52706141a7", "b7ed07e3877e913ac15244e3dadeb41770cc11e762f189f60edd9c78fe6bce29", "8e5d15cbd83aff0ea244084cad9ecd47eb21fee60ee4c846510a34f05dc2f3de", "4dd0822be686fd036d131707600dab32897a852b830e2b68b1393744f1e38c13", "02f9d7c454c7772feabfadd9a9e053100ae74a546863e658ca83dd729c828ac4", "9fa066e419eb00f914d3c7a8019ebe3171f408cab8c6fe3afbe7ff870febc0b8", "fb8e3cbe8f7d27db7ba51ae17768ce537d7e9a0dd2949c71c93c459263b545b3", "c9f2a4db3b9c6337c86d4636b3e795608ab8651e7949803ad57c92e5cd88c982", "e44a2314a7b11f6b7e46a65b252e562075d6f3402d892b3e68d71ee4fbe30cf4", "2ac987b2b11ce18e6d263df6efaac28f039febe6873464667368d5e81da98a57", "67eb3a6a26f8b1f5dd1aec4dbe40b083aefb265b63c8e17f9fd7fede47a4a3f4", "7524c16affe6d890f2c1da6e192a421a02b08e1ffe65379ebecf51c3c4d7bdc1", } func benchmarkWrite(size int64, b *testing.B) { var key [32]byte data := make([]byte, size) h, err := New128(key[:]) if err != nil { panic(err) } b.SetBytes(size) b.ResetTimer() for i := 0; i < b.N; i++ { h.Write(data) } } func BenchmarkWrite_8(b *testing.B) { benchmarkWrite(8, b) } func BenchmarkWrite_16(b *testing.B) { benchmarkWrite(16, b) } func BenchmarkWrite_64(b *testing.B) { benchmarkWrite(64, b) } func BenchmarkWrite_1K(b *testing.B) { benchmarkWrite(1024, b) } func BenchmarkWrite_8K(b *testing.B) { benchmarkWrite(8*1024, b) } func benchmarkSum64(size int64, b *testing.B) { var key [32]byte data := make([]byte, size) b.SetBytes(size) b.ResetTimer() for i := 0; i < b.N; i++ { Sum64(data, key[:]) } } func BenchmarkSum64_8(b *testing.B) { benchmarkSum64(8, b) } func BenchmarkSum64_16(b *testing.B) { benchmarkSum64(16, b) } func BenchmarkSum64_64(b *testing.B) { benchmarkSum64(64, b) } func BenchmarkSum64_1K(b *testing.B) { benchmarkSum64(1024, b) } func BenchmarkSum64_8K(b *testing.B) { benchmarkSum64(8*1024, b) } func benchmarkSum256(size int64, b *testing.B) { var key [32]byte data := make([]byte, size) b.SetBytes(size) b.ResetTimer() for i := 0; i < b.N; i++ { Sum(data, key[:]) } } func BenchmarkSum256_8(b *testing.B) { benchmarkSum256(8, b) } func BenchmarkSum256_16(b *testing.B) { benchmarkSum256(16, b) } func BenchmarkSum256_64(b *testing.B) { benchmarkSum256(64, b) } func BenchmarkSum256_1K(b *testing.B) { benchmarkSum256(1024, b) } func BenchmarkSum256_8K(b *testing.B) { benchmarkSum256(8*1024, b) } func BenchmarkSum256_1M(b *testing.B) { benchmarkSum256(1024*1024, b) } func BenchmarkSum256_5M(b *testing.B) { benchmarkSum256(5*1024*1024, b) } func BenchmarkSum256_10M(b *testing.B) { benchmarkSum256(10*1024*1024, b) } func BenchmarkSum256_25M(b *testing.B) { benchmarkSum256(25*1024*1024, b) } func benchmarkParallel(b *testing.B, size int) { c := runtime.GOMAXPROCS(0) var key [32]byte rng := rand.New(rand.NewSource(0xabadc0cac01a)) data := make([][]byte, c) for i := range data { data[i] = make([]byte, size) rng.Read(data[i]) } b.SetBytes(int64(size)) b.ResetTimer() counter := uint64(0) b.RunParallel(func(pb *testing.PB) { for pb.Next() { index := atomic.AddUint64(&counter, 1) Sum(data[int(index)%len(data)], key[:]) } }) } func BenchmarkParallel_1M(b *testing.B) { benchmarkParallel(b, 1024*1024) } func BenchmarkParallel_5M(b *testing.B) { benchmarkParallel(b, 5*1024*1024) } func BenchmarkParallel_10M(b *testing.B) { benchmarkParallel(b, 10*1024*1024) } func BenchmarkParallel_25M(b *testing.B) { benchmarkParallel(b, 25*1024*1024) }