meowhash 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []