meowhash 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c656d4783358e5a42260dd2485ec44f981d55f20ca3a844e0e93c5d9c0baf70a
4
+ data.tar.gz: e964dac5d53526c7db83cb832f12ff07e71269ab41fe76cbd10c4e8a13602311
5
+ SHA512:
6
+ metadata.gz: 53a5317408a40723ec248dc760641c8cc7679ded23ab634eb735f5c1c364941d6e8d994d2a00c6f4fc4cfd9074d45734c80c4e5295d8ce7388982babc6f11451
7
+ data.tar.gz: 38de55bc2e688a22fd4200c7edca5364810d8258a4592c315e4ceaa754b4aa87d31461974b33cfac5e866e44c91fe38a8c0e707587fe17d40bbf7187c0fc6528
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :deployment do
5
+ gem 'package_cloud'
6
+ gem 'rake'
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ zlib License
2
+
3
+ (C) Copyright 2018 Molly Rocket, Inc. (Meow Hash)
4
+ (C) Copyright 2018 Alex Snaps (wrapper)
5
+
6
+ This software is provided 'as-is', without any express or implied
7
+ warranty. In no event will the authors be held liable for any damages
8
+ arising from the use of this software.
9
+
10
+ Permission is granted to anyone to use this software for any purpose,
11
+ including commercial applications, and to alter it and redistribute it
12
+ freely, subject to the following restrictions:
13
+
14
+ 1. The origin of this software must not be misrepresented; you must not
15
+ claim that you wrote the original software. If you use this software
16
+ in a product, an acknowledgment in the product documentation would be
17
+ appreciated but is not required.
18
+ 2. Altered source versions must be plainly marked as such, and must not be
19
+ misrepresented as being the original software.
20
+ 3. This notice may not be removed or altered from any source distribution.
@@ -0,0 +1,34 @@
1
+ task :default => :test
2
+
3
+ # ==========================================================
4
+ # Packaging
5
+ # ==========================================================
6
+
7
+ GEMSPEC = eval(File.read('meowhash.gemspec'))
8
+
9
+ require 'rubygems/package_task'
10
+ Gem::PackageTask.new(GEMSPEC) do |pkg|
11
+ end
12
+
13
+ # ==========================================================
14
+ # Ruby Extension
15
+ # ==========================================================
16
+
17
+ require 'rake/extensiontask'
18
+ Rake::ExtensionTask.new('meowhash', GEMSPEC) do |ext|
19
+ ext.ext_dir = 'ext/meowhash'
20
+ ext.lib_dir = 'lib/meowhash'
21
+ end
22
+ task :build => :compile
23
+
24
+ # ==========================================================
25
+ # Testing
26
+ # ==========================================================
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new 'test' do |t|
30
+ t.test_files = FileList['test/test_*.rb']
31
+ end
32
+ task :test => :build
33
+
34
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ require "mkmf"
2
+
3
+ $CFLAGS = "-O3 -Wall -mavx -maes"
4
+
5
+ abort "Requires CLANG!" if CONFIG['CC'] != "clang"
6
+
7
+ create_makefile "meowhash/meowhash"
@@ -0,0 +1,255 @@
1
+ /* ========================================================================
2
+
3
+ Meow - A Fast Non-cryptographic Hash
4
+ (C) Copyright 2018 by Molly Rocket, Inc. (https://mollyrocket.com)
5
+
6
+ See https://mollyrocket.com/meowhash for details.
7
+
8
+ ========================================================================
9
+
10
+ zlib License
11
+
12
+ (C) Copyright 2018 Molly Rocket, Inc.
13
+
14
+ This software is provided 'as-is', without any express or implied
15
+ warranty. In no event will the authors be held liable for any damages
16
+ arising from the use of this software.
17
+
18
+ Permission is granted to anyone to use this software for any purpose,
19
+ including commercial applications, and to alter it and redistribute it
20
+ freely, subject to the following restrictions:
21
+
22
+ 1. The origin of this software must not be misrepresented; you must not
23
+ claim that you wrote the original software. If you use this software
24
+ in a product, an acknowledgment in the product documentation would be
25
+ appreciated but is not required.
26
+ 2. Altered source versions must be plainly marked as such, and must not be
27
+ misrepresented as being the original software.
28
+ 3. This notice may not be removed or altered from any source distribution.
29
+
30
+ ========================================================================
31
+
32
+ FAQ
33
+
34
+ Q: What is it?
35
+
36
+ A: Meow is a 128-bit non-cryptographic hash that operates at high speeds
37
+ on x64 and ARM processors that provide AES instructions. It is
38
+ designed to be truncatable to 64 and 32-bit hash values and still
39
+ retain good collision resistance.
40
+
41
+ Q: What is it GOOD for?
42
+
43
+ A: Quickly hashing any amount of data for comparison purposes such as
44
+ block deduplication or change detection. It is extremely fast on
45
+ all buffer sizes, from one byte to one gigabyte and up.
46
+
47
+ Q: What is it BAD for?
48
+
49
+ A: Anything security-related. It should be assumed that it provides
50
+ no protection from adversaries whatsoever. It is also not particularly
51
+ fast on processors that don't support AES instructions (eg., non-x64/ARM
52
+ processors).
53
+
54
+ Q: Why is it called the "Meow hash"?
55
+
56
+ A: It is named after a character in Meow the Infinite
57
+ (https://meowtheinfinite.com)
58
+
59
+ Q: Who wrote it?
60
+
61
+ A: CASEY MURATORI (https://caseymuratori.com) wrote the original
62
+ implementation for use in processing large-footprint assets for
63
+ the game 1935 (https://molly1935.com).
64
+
65
+ After the initial version, the hash was refined via collaboration
66
+ with several great programmers who contributed suggestions and
67
+ modifications:
68
+
69
+ JEFF ROBERTS (https://radgametools.com) provided a super slick
70
+ way to handle the residual end-of-buffer bytes that dramatically
71
+ improved Meow's small hash performance.
72
+
73
+ MARTINS MOZEIKO (https://matrins.ninja) ported Meow to ARM and
74
+ ANSI-C, and added the proper preprocessor dressing for clean
75
+ compilation on a variety of compiler configurations.
76
+
77
+ FABIAN GIESEN (https://fgiesen.wordpress.com) provided support
78
+ for getting the benchmarking working properly across a number
79
+ of platforms.
80
+
81
+ ARAS PRANCKEVICIUS (https://aras-p.info) provided the allocation
82
+ shim for compilation on Mac OS X.
83
+
84
+ ========================================================================
85
+
86
+ USAGE
87
+
88
+ For a complete working example, see meow_example.cpp. Briefly:
89
+
90
+ // Include meow_intrinsics if you want it to detect platforms
91
+ // and define types and intrinsics for you. Omit it if you
92
+ // want to define them yourself.
93
+ #include "meow_intrinsics.h"
94
+
95
+ // Include meow_hash for the Meow hash function
96
+ #include "meow_hash.h"
97
+
98
+ // Hash a block of data using CPU-specific acceleration
99
+ meow_u128 MeowHash_Accelerated(u64 Seed, u64 Len, void *Source);
100
+
101
+ // Check if two Meow hashes are the same
102
+ // (returns zero if they aren't, non-zero if they are)
103
+ int MeowHashesAreEqual(meow_u128 A, meow_u128 B)
104
+
105
+ // Truncate a Meow hash to 64 bits
106
+ meow_u64 MeowU64From(meow_u128 Hash);
107
+
108
+ // Truncate a Meow hash to 32 bits
109
+ meow_u32 MeowU32From(meow_u128 Hash);
110
+
111
+ **** VERY IMPORTANT X64 COMPILATION NOTES ****
112
+
113
+ On x64, Meow uses the AESDEC instruction, which comes in two flavors:
114
+ SSE (aesdec) and AVX (vaesdec). If you are compiling _with_ AVX support,
115
+ your compiler will probably emit the AVX variant, which means your code
116
+ WILL NOT RUN on computers that do not have AVX. If you need to deploy
117
+ this hash on computers that do not have AVX, you must take care to
118
+ TURN OFF support for AVX in your compiler for the file that includes
119
+ the Meow hash!
120
+
121
+ ======================================================================== */
122
+
123
+ //
124
+ // NOTE(casey): This version is EXPERIMENTAL. The Meow hash is still
125
+ // undergoing testing and finalization.
126
+ //
127
+ // **** EXPECT HASHES/APIs TO CHANGE UNTIL THE VERSION NUMBER HITS 1.0. ****
128
+ //
129
+ // You have been warned.
130
+ //
131
+
132
+ static const unsigned char MeowShiftAdjust[31] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128};
133
+ static const unsigned char MeowMaskLen[32] = {255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
134
+
135
+ // TODO(casey): These constants are loaded to initialize the lanes. Jacob should
136
+ // give us some feedback on what they should _actually_ be set to.
137
+ #define MEOW_S0_INIT { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12,13,14,15}
138
+ #define MEOW_S1_INIT {16,17,18,19, 20,21,22,23, 24,25,26,27, 28,29,30,31}
139
+ #define MEOW_S2_INIT {32,33,34,35, 36,37,38,39, 40,41,42,43, 44,45,46,47}
140
+ #define MEOW_S3_INIT {48,49,50,51, 52,53,54,55, 56,57,58,59, 60,61,62,63}
141
+ static const unsigned char MeowS0Init[] = MEOW_S0_INIT;
142
+ static const unsigned char MeowS1Init[] = MEOW_S1_INIT;
143
+ static const unsigned char MeowS2Init[] = MEOW_S2_INIT;
144
+ static const unsigned char MeowS3Init[] = MEOW_S3_INIT;
145
+
146
+ //
147
+ // NOTE(casey): 128-wide AES-NI Meow (maximum of 16 bytes/clock single threaded)
148
+ //
149
+
150
+ static meow_hash
151
+ MeowHash_Accelerated(meow_u64 Seed, meow_u64 TotalLengthInBytes, void *SourceInit)
152
+ {
153
+ //
154
+ // NOTE(casey): Initialize the four AES streams and the mixer
155
+ //
156
+
157
+ meow_aes_128 S0 = Meow128_GetAESConstant(MeowS0Init);
158
+ meow_aes_128 S1 = Meow128_GetAESConstant(MeowS1Init);
159
+ meow_aes_128 S2 = Meow128_GetAESConstant(MeowS2Init);
160
+ meow_aes_128 S3 = Meow128_GetAESConstant(MeowS3Init);
161
+
162
+ meow_u128 Mixer = Meow128_Set64x2(Seed - TotalLengthInBytes,
163
+ Seed + TotalLengthInBytes + 1);
164
+
165
+ //
166
+ // NOTE(casey): Handle as many full 256-byte blocks as possible
167
+ //
168
+
169
+ meow_u8 *Source = (meow_u8 *)SourceInit;
170
+ meow_u64 Len = TotalLengthInBytes;
171
+ int unsigned Len8 = Len & 15;
172
+ int unsigned Len128 = Len & 48;
173
+
174
+ while(Len >= 64)
175
+ {
176
+ S0 = Meow128_AESDEC_Mem(S0, Source);
177
+ S1 = Meow128_AESDEC_Mem(S1, Source + 16);
178
+ S2 = Meow128_AESDEC_Mem(S2, Source + 32);
179
+ S3 = Meow128_AESDEC_Mem(S3, Source + 48);
180
+
181
+ Len -= 64;
182
+ Source += 64;
183
+ }
184
+
185
+ //
186
+ // NOTE(casey): Overhanging individual bytes
187
+ //
188
+
189
+ if(Len8)
190
+ {
191
+ meow_u8 *Overhang = Source + Len128;
192
+ int Align = ((int)(meow_umm)Overhang) & 15;
193
+ if(Align)
194
+ {
195
+ int End = ((int)(meow_umm)Overhang) & (MEOW_PAGESIZE - 1);
196
+
197
+ // NOTE(jeffr): If we are nowhere near the page end, use full unaligned load (cmov to set)
198
+ if (End <= (MEOW_PAGESIZE - 16))
199
+ {
200
+ Align = 0;
201
+ }
202
+
203
+ // NOTE(jeffr): If we will read over the page end, use a full unaligned load (cmov to set)
204
+ if ((End + Len8) > MEOW_PAGESIZE)
205
+ {
206
+ Align = 0;
207
+ }
208
+
209
+ meow_u128 Partial = Meow128_Shuffle_Mem(Overhang - Align, &MeowShiftAdjust[Align]);
210
+
211
+ Partial = Meow128_And_Mem( Partial, &MeowMaskLen[16 - Len8] );
212
+ S3 = Meow128_AESDEC(S3, Partial);
213
+ }
214
+ else
215
+ {
216
+ // NOTE(casey): We don't have to do Jeff's heroics when we know the
217
+ // buffer is aligned, since we cannot span a memory page (by definition).
218
+ meow_u128 Partial = Meow128_And_Mem(*(meow_u128 *)Overhang, &MeowMaskLen[16 - Len8]);
219
+ S3 = Meow128_AESDEC(S3, Partial);
220
+ }
221
+ }
222
+
223
+ //
224
+ // NOTE(casey): Overhanging full 128-bit lanes
225
+ //
226
+
227
+ switch(Len128)
228
+ {
229
+ case 48: S2 = Meow128_AESDEC_Mem(S2, Source + 32);
230
+ case 32: S1 = Meow128_AESDEC_Mem(S1, Source + 16);
231
+ case 16: S0 = Meow128_AESDEC_Mem(S0, Source);
232
+ }
233
+
234
+ //
235
+ // NOTE(casey): Mix the four lanes down to one 128-bit hash
236
+ //
237
+
238
+ S3 = Meow128_AESDEC(S3, Mixer);
239
+ S2 = Meow128_AESDEC(S2, Mixer);
240
+ S1 = Meow128_AESDEC(S1, Mixer);
241
+ S0 = Meow128_AESDEC(S0, Mixer);
242
+
243
+ S2 = Meow128_AESDEC(S2, Meow128_AESDEC_Finalize(S3));
244
+ S0 = Meow128_AESDEC(S0, Meow128_AESDEC_Finalize(S1));
245
+
246
+ S2 = Meow128_AESDEC(S2, Mixer);
247
+
248
+ S0 = Meow128_AESDEC(S0, Meow128_AESDEC_Finalize(S2));
249
+ S0 = Meow128_AESDEC(S0, Mixer);
250
+
251
+ meow_hash Result;
252
+ Meow128_CopyToHash(Meow128_AESDEC_Finalize(S0), Result);
253
+
254
+ return(Result);
255
+ }
@@ -0,0 +1,261 @@
1
+ /* ========================================================================
2
+
3
+ meow_intrinsics.h
4
+ (C) Copyright 2018 by Molly Rocket, Inc. (https://mollyrocket.com)
5
+
6
+ See https://mollyrocket.com/meowhash for details.
7
+
8
+ This is the default way to define all of the types and operations that
9
+ meow_hash.h needs. However, if you've got your _own_ equivalent type
10
+ definitions and intrinsics, you can _omit_ this header file and just
11
+ #define/typedef all the Meow ops to map to your own ops, keeping things
12
+ nice and uniform in your codebase.
13
+
14
+ ======================================================================== */
15
+
16
+ #if !defined(MEOW_HASH_INTRINSICS_H)
17
+
18
+ //
19
+ // NOTE(casey): Try to guess the source file for compiler intrinsics
20
+ //
21
+ #if _MSC_VER
22
+
23
+ #if _M_AMD64 || _M_IX86
24
+ #include <intrin.h>
25
+ #elif _M_ARM64
26
+ #include <arm64_neon.h>
27
+ #endif
28
+
29
+ #else
30
+
31
+ #if __x86_64__ || __i386__
32
+ #include <x86intrin.h>
33
+ #elif __aarch64__
34
+ #include <arm_neon.h>
35
+ #endif
36
+
37
+ #endif
38
+
39
+ //
40
+ // NOTE(casey): Set #define's to their defaults
41
+ //
42
+
43
+ #if !defined(MEOW_HASH_INTEL) || !defined(MEOW_HASH_ARMV8)
44
+ #if __x86_64__ || _M_AMD64
45
+ #define MEOW_HASH_INTEL 1
46
+ #define MEOW_64BIT 1
47
+ #define MEOW_PAGESIZE 4096
48
+ #elif __i386__ || _M_IX86
49
+ #define MEOW_HASH_INTEL 1
50
+ #define MEOW_64BIT 0
51
+ #define MEOW_PAGESIZE 4096
52
+ #elif __aarch64__ || _M_ARM64
53
+ #define MEOW_HASH_ARMV8 1
54
+ #define MEOW_64BIT 1
55
+ #define MEOW_PAGESIZE 4096
56
+ #else
57
+ #error Cannot determine architecture to use!
58
+ #endif
59
+ #endif
60
+
61
+ //
62
+ // NOTE(casey): Define basic types
63
+ //
64
+
65
+ #define meow_u8 char unsigned
66
+ #define meow_u16 short unsigned
67
+ #define meow_u32 int unsigned
68
+ #define meow_u64 long long unsigned
69
+
70
+ #if MEOW_64BIT
71
+ #define meow_umm long long unsigned
72
+ #else
73
+ #define meow_umm int unsigned
74
+ #endif
75
+
76
+ //
77
+ // NOTE(casey): Operations for x64 processors
78
+ //
79
+
80
+ #if MEOW_HASH_INTEL
81
+
82
+ #define meow_u128 __m128i
83
+ #define meow_aes_128 __m128i
84
+ #define meow_u256 __m256i
85
+ #define meow_aes_256 __m256i
86
+ #define meow_u512 __m512i
87
+ #define meow_aes_512 __m512i
88
+
89
+ #define MeowU32From(A, I) (_mm_extract_epi32((A), (I)))
90
+ #define MeowU64From(A, I) (_mm_extract_epi64((A), (I)))
91
+ #define MeowHashesAreEqual(A, B) (_mm_movemask_epi8(_mm_cmpeq_epi8((A), (B))) == 0xFFFF)
92
+
93
+ #define Meow128_AESDEC(Prior, Xor) _mm_aesdec_si128((Prior), (Xor))
94
+ #define Meow128_AESDEC_Mem(Prior, Xor) _mm_aesdec_si128((Prior), _mm_loadu_si128((meow_u128 *)(Xor)))
95
+ #define Meow128_AESDEC_Finalize(A) (A)
96
+ #define Meow128_Set64x2(Low64, High64) _mm_set_epi64x((High64), (Low64))
97
+ #define Meow128_Set64x2_State(Low64, High64) Meow128_Set64x2(Low64, High64)
98
+ #define Meow128_GetAESConstant(Ptr) (*(meow_u128 *)(Ptr))
99
+
100
+ #define Meow128_And_Mem(A,B) _mm_and_si128((A),_mm_loadu_si128((meow_u128 *)(B)))
101
+ #define Meow128_Shuffle_Mem(Mem,Control) _mm_shuffle_epi8(_mm_loadu_si128((meow_u128 *)(Mem)),_mm_loadu_si128((meow_u128 *)(Control)))
102
+
103
+ // TODO(casey): Not sure if this should actually be Meow128_Zero(A) ((A) = _mm_setzero_si128()), maybe
104
+ #define Meow128_Zero() _mm_setzero_si128()
105
+
106
+ #define Meow256_AESDEC(Prior, XOr) _mm256_aesdec_epi128((Prior), (XOr))
107
+ #define Meow256_AESDEC_Mem(Prior, XOr) _mm256_aesdec_epi128((Prior), *(meow_u256 *)(XOr))
108
+ #define Meow256_Zero() _mm256_setzero_si256()
109
+ #define Meow256_PartialLoad(A, B) _mm256_mask_loadu_epi8(_mm256_setzero_si256(), _cvtu32_mask32((1UL<<(B)) - 1), (A))
110
+ #define Meow128_FromLow(A) _mm256_extracti128_si256((A), 0)
111
+ #define Meow128_FromHigh(A) _mm256_extracti128_si256((A), 1)
112
+
113
+ #define Meow512_AESDEC(Prior, XOr) _mm512_aesdec_epi128((Prior), (XOr))
114
+ #define Meow512_AESDEC_Mem(Prior, XOr) _mm512_aesdec_epi128((Prior), *(meow_u512 *)(XOr))
115
+ #define Meow512_Zero() _mm512_setzero_si512()
116
+ #define Meow512_PartialLoad(A, B) _mm512_mask_loadu_epi8(_mm512_setzero_si512(), _cvtu64_mask64((1ULL<<(B)) - 1), (A))
117
+ #define Meow256_FromLow(A) _mm512_extracti64x4_epi64((A), 0)
118
+ #define Meow256_FromHigh(A) _mm512_extracti64x4_epi64((A), 1)
119
+
120
+ //
121
+ // NOTE(casey): Operations for ARM processors
122
+ //
123
+
124
+ #elif MEOW_HASH_ARMV8
125
+
126
+ #define meow_u128 uint8x16_t
127
+
128
+ // NOTE(mmozeiko): AES opcodes on ARMv8 work a bit differently than on Intel
129
+ // On Intel the "x = AESDEC(x, m)" does following:
130
+ // x = InvMixColumns(SubBytes(ShiftRows(x))) ^ m
131
+ // But on ARMv8 the "x = AESDEC(x, m)" does following:
132
+ // x = SubBytes(ShiftRows(x ^ m))
133
+ // Thus on ARMv8 it requires extra InvMixColumns call and delay on Xor operation.
134
+ // On iteration N it needs to use m[N-1] as input, and remeber m[N] for next iteration.
135
+ // This structure will store memory operand in member B which will be used in
136
+ // next AESDEC opcode. Remember to do one more XOR(A,B) when finishing AES
137
+ // operations in a loop.
138
+ typedef struct {
139
+ meow_u128 A;
140
+ meow_u128 B;
141
+ } meow_aes_128;
142
+
143
+ #define MeowU32From(A, I) (vgetq_lane_u32(vreinterpretq_u32_u8((A)), (I)))
144
+ #define MeowU64From(A, I) (vgetq_lane_u64(vreinterpretq_u64_u8((A)), (I)))
145
+
146
+ static int
147
+ MeowHashesAreEqualImpl(meow_u128 A, meow_u128 B)
148
+ {
149
+ uint8x16_t Powers = {
150
+ 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128,
151
+ };
152
+
153
+ uint8x16_t Input = vceqq_u8(A, B);
154
+ uint64x2_t Mask = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vandq_u8(Input, Powers))));
155
+
156
+ meow_u16 Output;
157
+ vst1q_lane_u8((meow_u8*)&Output + 0, vreinterpretq_u8_u64(Mask), 0);
158
+ vst1q_lane_u8((meow_u8*)&Output + 1, vreinterpretq_u8_u64(Mask), 8);
159
+ return Output == 0xFFFF;
160
+ }
161
+
162
+ #define MeowHashesAreEqual(A, B) MeowHashesAreEqualImpl((A), (B))
163
+
164
+ static meow_aes_128
165
+ Meow128_AESDEC(meow_aes_128 Prior, meow_u128 Xor)
166
+ {
167
+ meow_aes_128 R;
168
+ R.A = vaesimcq_u8(vaesdq_u8(Prior.A, Prior.B));
169
+ R.B = Xor;
170
+ return(R);
171
+ }
172
+
173
+ static meow_aes_128
174
+ Meow128_AESDEC_Mem(meow_aes_128 Prior, void *Xor)
175
+ {
176
+ meow_aes_128 R;
177
+ R.A = vaesimcq_u8(vaesdq_u8(Prior.A, Prior.B));
178
+ R.B = vld1q_u8((meow_u8*)Xor);
179
+ return(R);
180
+ }
181
+
182
+ static meow_u128
183
+ Meow128_AESDEC_Finalize(meow_aes_128 Value)
184
+ {
185
+ meow_u128 R = veorq_u8(Value.A, Value.B);
186
+ return(R);
187
+ }
188
+
189
+ static meow_u128
190
+ Meow128_Zero()
191
+ {
192
+ meow_u128 R = vdupq_n_u8(0);
193
+ return(R);
194
+ }
195
+
196
+ static meow_aes_128
197
+ Meow128_GetAESConstant(const meow_u8 *Ptr)
198
+ {
199
+ meow_aes_128 R;
200
+ R.A = vld1q_u8(Ptr);
201
+ R.B = vdupq_n_u8(0);
202
+ return(R);
203
+ }
204
+
205
+ static meow_u128
206
+ Meow128_Set64x2(meow_u64 Low64, meow_u64 High64)
207
+ {
208
+ meow_u128 R = vreinterpretq_u8_u64(vcombine_u64(vcreate_u64(Low64), vcreate_u64(High64)));
209
+ return(R);
210
+ }
211
+
212
+ static meow_aes_128
213
+ Meow128_Set64x2_State(meow_u64 Low64, meow_u64 High64)
214
+ {
215
+ meow_aes_128 R;
216
+ R.A = Meow128_Set64x2(Low64, High64);
217
+ R.B = Meow128_Zero();
218
+ return(R);
219
+ }
220
+
221
+ #define Meow128_And_Mem(A,B) vandq_u8((A), vld1q_u8((meow_u8 *)B))
222
+ #define Meow128_Shuffle_Mem(Mem,Control) vqtbl1q_u8(vld1q_u8((meow_u8 *)(Mem)),vld1q_u8((meow_u8 *)(Control)))
223
+
224
+ #endif
225
+
226
+ #define MEOW_HASH_VERSION 4
227
+ #define MEOW_HASH_VERSION_NAME "0.4/himalayan"
228
+
229
+ #if MEOW_INCLUDE_C
230
+
231
+ // NOTE(casey): Unfortunately, if you want an ANSI-C version, we have to slow everyone
232
+ // else down because you can't return 128-bit values by register anymore (in case the
233
+ // CPU doesn't support that)
234
+ union meow_hash
235
+ {
236
+ meow_u128 u128;
237
+ meow_u64 u64[2];
238
+ meow_u32 u32[4];
239
+ };
240
+ #define Meow128_CopyToHash(A, B) ((B).u128 = (A))
241
+
242
+ #undef MeowU64From
243
+ #undef MeowU32From
244
+ #undef MeowHashesAreEqual
245
+ #define MeowU32From(A, I) ((A).u32[I])
246
+ #define MeowU64From(A, I) ((A).u64[I])
247
+ #define MeowHashesAreEqual(A, B) (((A).u32[0] == (B).u32[0]) && ((A).u32[1] == (B).u32[1]) && ((A).u32[2] == (B).u32[2]) && ((A).u32[3] == (B).u32[3]))
248
+
249
+ #else
250
+
251
+ typedef meow_u128 meow_hash;
252
+ #define Meow128_CopyToHash(A, B) ((B) = (A))
253
+
254
+ #endif
255
+
256
+ typedef struct meow_hash_state meow_hash_state;
257
+ typedef meow_hash meow_hash_implementation(meow_u64 Seed, meow_u64 Len, void *Source);
258
+ typedef void meow_absorb_implementation(struct meow_hash_state *State, meow_u64 Len, void *Source);
259
+
260
+ #define MEOW_HASH_INTRINSICS_H
261
+ #endif
@@ -0,0 +1,48 @@
1
+ #include <ruby.h>
2
+
3
+ #include "meow_intrinsics.h"
4
+ #include "meow_hash.h"
5
+
6
+ #define VERSION "0.4"
7
+
8
+ /*
9
+ */
10
+ static VALUE
11
+ rb_meow_version(int argc, VALUE *argv, VALUE klass)
12
+ {
13
+ return rb_sprintf("v%s", VERSION);
14
+ }
15
+
16
+ static void
17
+ to_chars(unsigned long n, unsigned char *bytes)
18
+ {
19
+ bytes[0] = (n >> 24) & 0xFF;
20
+ bytes[1] = (n >> 16) & 0xFF;
21
+ bytes[2] = (n >> 8) & 0xFF;
22
+ bytes[3] = n & 0xFF;
23
+ }
24
+
25
+ static VALUE
26
+ rb_meow_hash(VALUE self, VALUE toHash)
27
+ {
28
+ Check_Type(toHash, T_STRING);
29
+
30
+ meow_hash Hash = MeowHash_Accelerated(0, RSTRING_LEN(toHash), StringValuePtr(toHash));
31
+ unsigned char buffer[16];
32
+ to_chars(MeowU32From(Hash, 3), &buffer[0]);
33
+ to_chars(MeowU32From(Hash, 2), &buffer[4]);
34
+ to_chars(MeowU32From(Hash, 1), &buffer[8]);
35
+ to_chars(MeowU32From(Hash, 0), &buffer[12]);
36
+ VALUE rb_binary = rb_str_new(buffer, 16);
37
+ return rb_binary;
38
+ }
39
+
40
+ void
41
+ Init_meowhash()
42
+ {
43
+ VALUE mMH = rb_define_module("MeowHash");
44
+ VALUE cHasher = rb_define_module_under(mMH, "Hasher");
45
+
46
+ rb_define_module_function(cHasher, "version", rb_meow_version, 0);
47
+ rb_define_module_function(cHasher, "digest", rb_meow_hash, 1);
48
+ }
@@ -0,0 +1 @@
1
+ require 'meowhash/meowhash'
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'meowhash'
3
+ s.version = '0.4.0'
4
+ s.summary = 'Meow Hash for Ruby'
5
+ s.description = <<-DOC
6
+ Meow Hash C extension for Ruby
7
+ DOC
8
+ s.homepage = 'https://github.com/alexsnaps/meowhash'
9
+ s.authors = ['Alex Snaps']
10
+ s.email = ['alex.snaps@gmail.com']
11
+ s.license = 'zlib'
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.extensions = ['ext/meowhash/extconf.rb']
15
+ s.add_development_dependency 'rake-compiler', '~> 1.0'
16
+ s.add_development_dependency 'test-unit'
17
+ end
@@ -0,0 +1,28 @@
1
+ require 'test/unit'
2
+ require 'meowhash'
3
+
4
+ class TestMeowHash < Test::Unit::TestCase
5
+ def test_version
6
+ assert MeowHash::Hasher.version() == "v0.4"
7
+ end
8
+
9
+ def test_hasher
10
+ assert_equal("0591045C3C3F33B515D7D2E366FBF082".downcase, MeowHash::Hasher.digest("toto").each_byte.map { |b| b.to_s(16).rjust(2,'0') }.join)
11
+ end
12
+
13
+ def test_raises_on_non_string
14
+ assert_raise TypeError do
15
+ MeowHash::Hasher.digest(42)
16
+ end
17
+ end
18
+
19
+ def test_meow_hash_version
20
+ file = File.open("ext/meowhash/meow_hash.h", "rb")
21
+ assert_equal("9F177F35D31536CDE904FF01EE0E9A72".downcase, MeowHash::Hasher.digest(file.read).each_byte.map { |b| b.to_s(16).rjust(2,'0') }.join)
22
+ end
23
+
24
+ def test_meow_intrinsics_version
25
+ file = File.open("ext/meowhash/meow_intrinsics.h", "rb")
26
+ assert_equal("B6F0D59805A037BFFC13AF959E08CC92".downcase, MeowHash::Hasher.digest(file.read).each_byte.map { |b| b.to_s(16).rjust(2,'0') }.join)
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meowhash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Snaps
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake-compiler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: test-unit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: " Meow Hash C extension for Ruby\n"
42
+ email:
43
+ - alex.snaps@gmail.com
44
+ executables: []
45
+ extensions:
46
+ - ext/meowhash/extconf.rb
47
+ extra_rdoc_files: []
48
+ files:
49
+ - Gemfile
50
+ - LICENSE
51
+ - Rakefile
52
+ - ext/meowhash/extconf.rb
53
+ - ext/meowhash/meow_hash.h
54
+ - ext/meowhash/meow_intrinsics.h
55
+ - ext/meowhash/meowhash.c
56
+ - lib/meowhash.rb
57
+ - meowhash.gemspec
58
+ - test/test_meowhash.rb
59
+ homepage: https://github.com/alexsnaps/meowhash
60
+ licenses:
61
+ - zlib
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.7.6
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Meow Hash for Ruby
83
+ test_files: []