├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── aeshash.go ├── aeshash.s ├── aeshash └── aeshash.go ├── aeshashCompat.go ├── aeshash_test.go ├── example └── example.go ├── go.mod └── go.sum /.gitattributes: -------------------------------------------------------------------------------- 1 | *.s linguist-detectable=false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aeshash 2 | aeshash is a fast hash function extracted from the Go runtime that uses the Intel AESENC instruction. Used by Go's map. 3 | -------------------------------------------------------------------------------- /aeshash.go: -------------------------------------------------------------------------------- 1 | package aeshash 2 | 3 | import ( 4 | _ "unsafe" 5 | 6 | "leb.io/hashland/nhash" 7 | ) 8 | 9 | const hashRandomBytes = 32 // used in asm_{386,amd64}.s 10 | var masks [32]uint64 11 | var shifts [32]uint64 12 | var aeskeysched [hashRandomBytes]byte // this is really 2 x 128 bit round keys 13 | var aesdebug [hashRandomBytes]byte 14 | 15 | func aeshashbody() 16 | 17 | // Use these functions for higest speed 18 | func Hash(b []byte, seed uint64) uint64 19 | func HashStr(s string, seed uint64) uint64 20 | func Hash64(v uint64, s uint64) uint64 21 | func Hash32(v uint32, s uint64) uint64 22 | 23 | func init() { 24 | p := aeskeysched[:] 25 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] = 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 26 | p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] = 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10 27 | p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23] = 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 28 | p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31] = 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF 29 | p = aesdebug[:] 30 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] = 0xFF, 0, 0, 0, 0, 0, 0, 0xFE 31 | p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] = 0xFD, 0, 0, 0, 0, 0, 0, 0xFC 32 | } 33 | 34 | // 35 | type State struct { 36 | hash uint64 37 | seed uint64 38 | clen int 39 | tail []byte 40 | } 41 | 42 | func n(seed uint64) *State { 43 | s := new(State) 44 | s.seed = seed 45 | s.Reset() 46 | return s 47 | } 48 | 49 | // New returns state used for a aeshash. 50 | func New(seed uint64) nhash.Hash64 { 51 | s := n(seed) 52 | return s 53 | } 54 | 55 | // Size returns the size of the resulting hash. 56 | func (s *State) Size() int { return 8 } 57 | 58 | // BlockSize returns the blocksize of the hash which in this case is 1 byte. 59 | func (s *State) BlockSize() int { return 1 } 60 | 61 | // NumSeedBytes returns the maximum number of seed bypes required. In this case 2 x 32 62 | func (s *State) NumSeedBytes() int { 63 | return 8 64 | } 65 | 66 | // HashSizeInBits returns the number of bits the hash function outputs. 67 | func (s *State) HashSizeInBits() int { 68 | return 64 69 | } 70 | 71 | // Reset the hash state. 72 | func (s *State) Reset() { 73 | s.hash = 0 74 | s.clen = 0 75 | s.tail = nil 76 | } 77 | 78 | // Write accepts a byte stream p used for calculating the hash. For now this call is lazy and the actual hash calculations take place in Sum() and Sum32(). 79 | func (s *State) Write(p []byte) (nn int, err error) { 80 | l := len(p) 81 | s.clen += l 82 | s.tail = append(s.tail, p...) 83 | return l, nil 84 | } 85 | 86 | // Write64 accepts a uint64 stream p used for calculating the hash. For now this call is lazy and the actual hash calculations take place in Sum() and Sum32(). 87 | func (s *State) Write64(h uint64) (err error) { 88 | s.clen += 8 89 | s.tail = append(s.tail, byte(h>>56), byte(h>>48), byte(h>>40), byte(h>>32), byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 90 | return nil 91 | } 92 | 93 | // Sum returns the current hash as a byte slice. 94 | func (s *State) Sum(b []byte) []byte { 95 | s.hash = Hash(s.tail, s.seed) 96 | h := s.hash 97 | return append(b, byte(h>>56), byte(h>>48), byte(h>>40), byte(h>>32), byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 98 | } 99 | 100 | // Sum64 returns the current hash as a 64 bit unsigned type. 101 | func (s *State) Sum64() uint64 { 102 | s.hash = Hash(s.tail, s.seed) 103 | return s.hash 104 | } 105 | -------------------------------------------------------------------------------- /aeshash.s: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 Lawrence E. Bakst. All rights reserved. 2 | // Copyright 2009 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // Go's hash function used by map on X64 hardware with AESNI 7 | // liberated from go runtime/asm_amd64.s 8 | 9 | #include "textflag.h" 10 | #include "funcdata.h" 11 | 12 | // func Hash(b []byte, seed uint64) uint64 13 | TEXT ·Hash(SB),NOSPLIT,$0-40 14 | MOVQ b_base+0(FP), AX // ptr to bytes 15 | MOVQ b_len+8(FP), CX // length of slice 16 | MOVQ seed+24(FP), X0 // seed to low 64 bits of xmm0 17 | CALL ·aeshashbody(SB) 18 | MOVQ X0, ret+32(FP) 19 | RET 20 | 21 | // func HashStr(s string, seed uint64) uint64 22 | TEXT ·HashStr(SB),NOSPLIT,$0-32 23 | MOVQ s_base+0(FP), AX // ptr to string data 24 | MOVQ s_len+8(FP), CX // length of string 25 | MOVQ seed+16(FP), X0 // seed to low 64 bits of xmm0 26 | CALL ·aeshashbody(SB) 27 | MOVQ X0, ret+24(FP) 28 | RET 29 | 30 | // AX: data 31 | // CX: length 32 | // X0: seed 33 | // func aeshashbody() 34 | TEXT ·aeshashbody(SB),NOSPLIT,$0-0 35 | PINSRQ $1, CX, X0 // size to high 64 bits of xmm0 36 | MOVO ·aeskeysched+0(SB), X2 37 | MOVO ·aeskeysched+16(SB), X3 38 | CMPQ CX, $16 39 | JB aessmall 40 | aesloop: 41 | CMPQ CX, $16 42 | JBE aesloopend 43 | MOVOU (AX), X1 44 | AESENC X2, X0 45 | AESENC X1, X0 46 | SUBQ $16, CX 47 | ADDQ $16, AX 48 | JMP aesloop 49 | // 1-16 bytes remaining 50 | aesloopend: 51 | // This load may overlap with the previous load above. 52 | // We'll hash some bytes twice, but that's ok. 53 | MOVOU -16(AX)(CX*1), X1 54 | JMP partial 55 | // 0-15 bytes 56 | aessmall: 57 | TESTQ CX, CX 58 | JE finalize // 0 bytes 59 | 60 | CMPB AX, $0xf0 61 | JA highpartial 62 | 63 | // 16 bytes loaded at this address won't cross 64 | // a page boundary, so we can load it directly. 65 | MOVOU (AX), X1 66 | ADDQ CX, CX 67 | MOVQ $masks<>(SB), BP 68 | PAND (BP)(CX*8), X1 69 | JMP partial 70 | highpartial: 71 | // address ends in 1111xxxx. Might be up against 72 | // a page boundary, so load ending at last byte. 73 | // Then shift bytes down using pshufb. 74 | MOVOU -16(AX)(CX*1), X1 75 | ADDQ CX, CX 76 | MOVQ $shifts<>(SB), BP 77 | PSHUFB (BP)(CX*8), X1 78 | partial: 79 | // incorporate partial block into hash 80 | AESENC X3, X0 81 | AESENC X1, X0 82 | finalize: 83 | // finalize hash 84 | AESENC X2, X0 85 | AESENC X3, X0 86 | AESENC X2, X0 87 | aesret: 88 | RET 89 | 90 | 91 | // put the seed s into the low 64 bits of xmm0 92 | // put the data v into the high 64 bits of xmm0 93 | // perform 3 AES rounds with 2 alternating round keys 94 | // func Hash64(k uint64, seed uint64) uint64 95 | TEXT ·Hash64(SB),NOSPLIT,$0-24 96 | MOVQ seed+8(FP), X0 // seed 97 | MOVQ k+0(FP), AX // data 98 | PINSRQ $1, AX, X0 // 64 bit data key to high order 64 bits of X0 99 | AESENC ·aeskeysched+0(SB), X0 100 | AESENC ·aeskeysched+16(SB), X0 101 | AESENC ·aeskeysched+0(SB), X0 102 | MOVQ X0, ret+16(FP) 103 | RET 104 | 105 | // func Hash32(k uint32, seed uint64) uint64 106 | TEXT ·Hash32(SB),NOSPLIT,$0-24 107 | MOVQ seed+8(FP), X0 // seed 108 | MOVQ k+0(FP), AX // 32 bit data key 109 | PINSRD $2, AX, X0 // data to the low order 32 bits of the high order 64 bits 110 | PINSRD $3, AX, X0 // data to the high order 32 bits of the high order 64 bits 111 | AESENC ·aeskeysched+0(SB), X0 112 | AESENC ·aeskeysched+16(SB), X0 113 | AESENC ·aeskeysched+0(SB), X0 114 | MOVQ X0, ret+16(FP) 115 | RET 116 | 117 | 118 | // simple mask to get rid of data in the high part of the register. 119 | // var masks [32]uint64 120 | DATA masks<>+0x00(SB)/8, $0x0000000000000000 121 | DATA masks<>+0x08(SB)/8, $0x0000000000000000 122 | DATA masks<>+0x10(SB)/8, $0x00000000000000ff 123 | DATA masks<>+0x18(SB)/8, $0x0000000000000000 124 | DATA masks<>+0x20(SB)/8, $0x000000000000ffff 125 | DATA masks<>+0x28(SB)/8, $0x0000000000000000 126 | DATA masks<>+0x30(SB)/8, $0x0000000000ffffff 127 | DATA masks<>+0x38(SB)/8, $0x0000000000000000 128 | DATA masks<>+0x40(SB)/8, $0x00000000ffffffff 129 | DATA masks<>+0x48(SB)/8, $0x0000000000000000 130 | DATA masks<>+0x50(SB)/8, $0x000000ffffffffff 131 | DATA masks<>+0x58(SB)/8, $0x0000000000000000 132 | DATA masks<>+0x60(SB)/8, $0x0000ffffffffffff 133 | DATA masks<>+0x68(SB)/8, $0x0000000000000000 134 | DATA masks<>+0x70(SB)/8, $0x00ffffffffffffff 135 | DATA masks<>+0x78(SB)/8, $0x0000000000000000 136 | DATA masks<>+0x80(SB)/8, $0xffffffffffffffff 137 | DATA masks<>+0x88(SB)/8, $0x0000000000000000 138 | DATA masks<>+0x90(SB)/8, $0xffffffffffffffff 139 | DATA masks<>+0x98(SB)/8, $0x00000000000000ff 140 | DATA masks<>+0xa0(SB)/8, $0xffffffffffffffff 141 | DATA masks<>+0xa8(SB)/8, $0x000000000000ffff 142 | DATA masks<>+0xb0(SB)/8, $0xffffffffffffffff 143 | DATA masks<>+0xb8(SB)/8, $0x0000000000ffffff 144 | DATA masks<>+0xc0(SB)/8, $0xffffffffffffffff 145 | DATA masks<>+0xc8(SB)/8, $0x00000000ffffffff 146 | DATA masks<>+0xd0(SB)/8, $0xffffffffffffffff 147 | DATA masks<>+0xd8(SB)/8, $0x000000ffffffffff 148 | DATA masks<>+0xe0(SB)/8, $0xffffffffffffffff 149 | DATA masks<>+0xe8(SB)/8, $0x0000ffffffffffff 150 | DATA masks<>+0xf0(SB)/8, $0xffffffffffffffff 151 | DATA masks<>+0xf8(SB)/8, $0x00ffffffffffffff 152 | GLOBL masks<>(SB), RODATA, $256 153 | 154 | // these are arguments to pshufb. They move data down from 155 | // the high bytes of the register to the low bytes of the register. 156 | // index is how many bytes to move. 157 | // var shifts [32]uint64 158 | DATA shifts<>+0x00(SB)/8, $0x0000000000000000 159 | DATA shifts<>+0x08(SB)/8, $0x0000000000000000 160 | DATA shifts<>+0x10(SB)/8, $0xffffffffffffff0f 161 | DATA shifts<>+0x18(SB)/8, $0xffffffffffffffff 162 | DATA shifts<>+0x20(SB)/8, $0xffffffffffff0f0e 163 | DATA shifts<>+0x28(SB)/8, $0xffffffffffffffff 164 | DATA shifts<>+0x30(SB)/8, $0xffffffffff0f0e0d 165 | DATA shifts<>+0x38(SB)/8, $0xffffffffffffffff 166 | DATA shifts<>+0x40(SB)/8, $0xffffffff0f0e0d0c 167 | DATA shifts<>+0x48(SB)/8, $0xffffffffffffffff 168 | DATA shifts<>+0x50(SB)/8, $0xffffff0f0e0d0c0b 169 | DATA shifts<>+0x58(SB)/8, $0xffffffffffffffff 170 | DATA shifts<>+0x60(SB)/8, $0xffff0f0e0d0c0b0a 171 | DATA shifts<>+0x68(SB)/8, $0xffffffffffffffff 172 | DATA shifts<>+0x70(SB)/8, $0xff0f0e0d0c0b0a09 173 | DATA shifts<>+0x78(SB)/8, $0xffffffffffffffff 174 | DATA shifts<>+0x80(SB)/8, $0x0f0e0d0c0b0a0908 175 | DATA shifts<>+0x88(SB)/8, $0xffffffffffffffff 176 | DATA shifts<>+0x90(SB)/8, $0x0e0d0c0b0a090807 177 | DATA shifts<>+0x98(SB)/8, $0xffffffffffffff0f 178 | DATA shifts<>+0xa0(SB)/8, $0x0d0c0b0a09080706 179 | DATA shifts<>+0xa8(SB)/8, $0xffffffffffff0f0e 180 | DATA shifts<>+0xb0(SB)/8, $0x0c0b0a0908070605 181 | DATA shifts<>+0xb8(SB)/8, $0xffffffffff0f0e0d 182 | DATA shifts<>+0xc0(SB)/8, $0x0b0a090807060504 183 | DATA shifts<>+0xc8(SB)/8, $0xffffffff0f0e0d0c 184 | DATA shifts<>+0xd0(SB)/8, $0x0a09080706050403 185 | DATA shifts<>+0xd8(SB)/8, $0xffffff0f0e0d0c0b 186 | DATA shifts<>+0xe0(SB)/8, $0x0908070605040302 187 | DATA shifts<>+0xe8(SB)/8, $0xffff0f0e0d0c0b0a 188 | DATA shifts<>+0xf0(SB)/8, $0x0807060504030201 189 | DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09 190 | GLOBL shifts<>(SB), RODATA, $256 191 | 192 | -------------------------------------------------------------------------------- /aeshash/aeshash.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | _ "unsafe" 8 | 9 | "leb.io/aeshash" 10 | ) 11 | 12 | const blockSize = 1024 * 1024 13 | 14 | func readFullAESHash(path string) (r uint64) { 15 | //fmt.Printf("readFullAESHash: file=%q\n", path) 16 | f, err := os.Open(path) 17 | if err != nil { 18 | fmt.Printf("file %q, err=%v", path, err) 19 | } 20 | defer f.Close() 21 | 22 | buf := make([]byte, blockSize) 23 | hf := aeshash.NewAES(0) 24 | hf.Reset() 25 | for { 26 | l, err := f.Read(buf) 27 | //fmt.Printf("f=%q, err=%v, l=%d, size=%d\n", fi.Name(), err, l, fi.Size()) 28 | if l == 0 { 29 | break 30 | } 31 | if l < 0 || err != nil { 32 | fmt.Printf("file %q, err=%v", path, err) 33 | return 34 | } 35 | hf.Write(buf[:l]) 36 | } 37 | r = hf.Sum64() 38 | //fmt.Printf("readFullHash: p=%q, r=%#016x\n", p, r) 39 | //h.Write(buf[0:l]) 40 | //r = h.Sum64() 41 | //fmt.Printf("readFullHash: file=%q, hash=0x%016x\n", p, r) 42 | return r 43 | } 44 | 45 | func main() { 46 | var arg = flag.Uint64("i", 0, "number to hash") 47 | var seed = flag.Uint64("s", 0, "seed to hash") 48 | var zero = flag.Bool("z", false, "hash of 0") 49 | 50 | flag.Parse() 51 | switch { 52 | case *arg != 0 || *zero: 53 | fmt.Printf("%#016x\n", aeshash.Hash64(*arg, *seed)) 54 | default: 55 | if len(flag.Args()) <= 0 { 56 | return 57 | } 58 | //fmt.Printf("main: nargs=%d\n", len(flag.Args())) 59 | for _, path := range flag.Args() { 60 | h := readFullAESHash(path) 61 | fmt.Printf("%016x\t%s\n", h, path) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /aeshashCompat.go: -------------------------------------------------------------------------------- 1 | package aeshash 2 | 3 | import ( 4 | "leb.io/hashland/nhash" 5 | ) 6 | 7 | // nhash compatible interface 8 | func NewAES(seed uint64) nhash.Hash64 { 9 | s := n(seed) 10 | return s 11 | } 12 | 13 | func (s *State) Hash64(b []byte, seeds ...uint64) uint64 { 14 | switch len(seeds) { 15 | case 1: 16 | s.seed = seeds[0] 17 | } 18 | s.hash = Hash(b, s.seed) 19 | //fmt.Printf("pc=0x%08x, pb=0x%08x\n", d.pc, d.pb) 20 | return s.hash 21 | } 22 | 23 | //func Hash(p unsafe.Pointer, s, h uintptr) uintptr 24 | //func HashStr(p string, s, h uintptr) uintptr 25 | //func aeshash(p unsafe.Pointer, s, h uintptr) uintptr 26 | //func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr 27 | //func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr 28 | //func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr 29 | -------------------------------------------------------------------------------- /aeshash_test.go: -------------------------------------------------------------------------------- 1 | package aeshash 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUnseededHash(t *testing.T) { 8 | m := map[uint64]struct{}{} 9 | for i := 0; i < 1000; i++ { 10 | h := NewAES(uint64(i)) 11 | m[h.Sum64()] = struct{}{} 12 | } 13 | if len(m) < 900 { 14 | t.Errorf("empty hash not sufficiently random: got %d, want 1000", len(m)) 15 | } 16 | } 17 | 18 | func TestSeededHash(t *testing.T) { 19 | m := map[uint64]struct{}{} 20 | for i := 0; i < 1000; i++ { 21 | h := NewAES(1) 22 | m[h.Sum64()] = struct{}{} 23 | } 24 | if len(m) != 1 { 25 | t.Errorf("seeded hash is random: got %d, want 1", len(m)) 26 | } 27 | } 28 | 29 | /* 30 | func TestFirstTenHashes(t *testing.T) { 31 | var firstTenHashes = []uint64{ 32 | 0x54de6ee3c89ad535, 33 | 0x54de6ee3c89ad535, 34 | 0xd569b4f2ca17ba57, 35 | 0x02e52663b7589218, 36 | 0xbaba7ca05ac2c5e8, 37 | 0xd2446078b660d417, 38 | 0x89485dc9a8a45ce3, 39 | 0xd72a00044a27326f, 40 | 0x4af060bd80b05767, 41 | 0xb457cd9b9b95cdbf, 42 | 0x8782428a7c5cd1be, 43 | } 44 | */ 45 | 46 | func TestHash64(t *testing.T) { 47 | m := map[uint64]struct{}{} 48 | for i := 0; i < 1000; i++ { 49 | h := NewAES(1) 50 | m[h.Sum64()] = struct{}{} 51 | } 52 | if len(m) != 1 { 53 | t.Errorf("seeded hash is random: got %d, want 1", len(m)) 54 | } 55 | } 56 | 57 | func benchmarkStdSize(b *testing.B, size int) { 58 | h := NewAES(1) 59 | buf := make([]byte, size) 60 | b.SetBytes(int64(size)) 61 | b.ResetTimer() 62 | 63 | for i := 0; i < b.N; i++ { 64 | h.Reset() 65 | h.Write(buf) 66 | h.Sum64() 67 | } 68 | } 69 | 70 | func benchmarkSize(b *testing.B, size int) { 71 | buf := make([]byte, size) 72 | b.SetBytes(int64(size)) 73 | b.ResetTimer() 74 | 75 | for i := 0; i < b.N; i++ { 76 | Hash(buf, uint64(i)) 77 | } 78 | } 79 | 80 | func BenchmarkHash8Bytes(b *testing.B) { 81 | benchmarkSize(b, 8) 82 | } 83 | 84 | func BenchmarkHash320Bytes(b *testing.B) { 85 | benchmarkSize(b, 320) 86 | } 87 | 88 | func BenchmarkHash1K(b *testing.B) { 89 | benchmarkSize(b, 1024) 90 | } 91 | 92 | func BenchmarkHash8K(b *testing.B) { 93 | benchmarkSize(b, 8192) 94 | } 95 | 96 | func BenchmarkHash32(b *testing.B) { 97 | b.ResetTimer() 98 | 99 | for i := 0; i < b.N; i++ { 100 | Hash32(uint32(i), uint64(0)) 101 | } 102 | } 103 | 104 | func BenchmarkHash64(b *testing.B) { 105 | b.ResetTimer() 106 | 107 | for i := 0; i < b.N; i++ { 108 | Hash64(uint64(i), uint64(0)) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | _ "unsafe" 6 | 7 | "leb.io/aeshash" 8 | ) 9 | 10 | var strs = []string{"abcd", "efgh", "blow", "deadbeef"} 11 | var ui32 = []uint32{1, 2, 3, 4} 12 | var ui64 = []uint64{1, 2, 3, 4, 5, 6, 7, 8} 13 | var hash uint64 14 | 15 | func main() { 16 | for _, v := range strs { 17 | for seed := uint32(0); seed < 2; seed++ { 18 | b := make([]byte, 8) 19 | b = b[:] 20 | //copy(b, v) 21 | s := uint64(seed) 22 | //h := uint64(0) 23 | //pb := &i8[k] 24 | //up := unsafe.Pointer(v) 25 | //fmt.Printf("s=%d, h=%d\n", s, h) 26 | copy(b, v) 27 | b = b[0:len(v)] 28 | //hash := aeshash.HashStr(v, s) 29 | hash := aeshash.Hash(b, s) 30 | fmt.Printf("key=%v, seed=%d, hash=0x%016x\n", v, seed, hash) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module leb.io/aeshash 2 | 3 | go 1.17 4 | 5 | require leb.io/hashland v0.1.4 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/alecthomas/binary v0.0.0-20190922233330-fb1b1d9c299c/go.mod h1:v4e05/vzE8ubOim1No9Xx5eIQ/WRq6AtcnQIy/Z/JPs= 2 | github.com/dataence/bloom v0.0.0-20151026233158-e24b032dccb1/go.mod h1:hQ0yBWNA+0SlYMlAkHsylNyF2c85ZPgnJ6pvMOkzpRY= 3 | github.com/dataence/cityhash v0.0.0-20131128155616-cdd6a94144ab/go.mod h1:8k8m9EQDOnG3a2Z27FvW8LPScFO9P2JglEeq2kjKP9Y= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= 6 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= 7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 8 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 11 | github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= 12 | github.com/zhenjl/bloom v0.0.0-20151026233158-e24b032dccb1/go.mod h1:m5109HBotwhAcpovJ+nory3OI1OrcUmaluV7vxjX+ig= 13 | github.com/zhenjl/cityhash v0.0.0-20131128155616-cdd6a94144ab/go.mod h1:P6L88wrqK99Njntah9SB7AyzFpUXsXYq06LkjixxQmY= 14 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 15 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 16 | leb.io/aeshash v0.0.0-20190627052759-9e6b40329b3b/go.mod h1:BKjvdzZnV5WaMoO/kz/Fygl60dA79GTFQTSuKJmSdNs= 17 | leb.io/cuckoo v0.1.2/go.mod h1:EAn6JQBg65dcILMLuPbBRbkSjd6u+4KA+iTwBEUxBuQ= 18 | leb.io/hashes v0.1.1/go.mod h1:FjHpnSCaPTgHf+IkGEOVFtQfTXAQP5d0v6V2JmUNX8w= 19 | leb.io/hashland v0.0.0-20171003003232-07375b562dea/go.mod h1:OSwp5BNKniWS6joctn4Grabrxd2EERBB7pNzK9Ni3BQ= 20 | leb.io/hashland v0.1.4 h1:d1qPBJU/Pg5/aVmvrWq3PRKMsk41SJ1N/5l+uTYwwSE= 21 | leb.io/hashland v0.1.4/go.mod h1:1keOvdwSVl/iL0sZMN983BgUXwcTqWLsKKuj/C1UWtQ= 22 | leb.io/hrff v0.1.0/go.mod h1:EZ02Yctbwtxev2S/3jw6aKNrw2e/gkaaRk4fgnYFTec= 23 | --------------------------------------------------------------------------------