/src/p11-kit/common/hash.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2004, 2005, 2007, 2011 Internet Systems Consortium, Inc. ("ISC") |
3 | | * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. |
4 | | * |
5 | | * Permission to use, copy, modify, and/or distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
10 | | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
11 | | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
12 | | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
13 | | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
14 | | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
15 | | * PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | /*! \file |
19 | | * SHA-1 in C |
20 | | * \author By Steve Reid <steve@edmweb.com> |
21 | | * 100% Public Domain |
22 | | * \verbatim |
23 | | * Test Vectors |
24 | | * "abc" |
25 | | * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D |
26 | | * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" |
27 | | * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 |
28 | | * A million repetitions of "a" |
29 | | * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F |
30 | | * \endverbatim |
31 | | */ |
32 | | |
33 | | #include "config.h" |
34 | | |
35 | | #include "hash.h" |
36 | | |
37 | | #include <assert.h> |
38 | | #include <stdarg.h> |
39 | | #include <stdint.h> |
40 | | #include <string.h> |
41 | | |
42 | | /* This code is based on the public domain MurmurHash3 from Austin Appleby: |
43 | | * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp |
44 | | * |
45 | | * We use only the 32 bit variant, and slow it down a bit to support unaligned |
46 | | * reads. |
47 | | */ |
48 | | |
49 | | #if !defined(__cplusplus) && (__GNUC__ > 2) |
50 | | #define GNUC_INLINE __attribute__((always_inline)) |
51 | | #else |
52 | | #define GNUC_INLINE |
53 | | #endif |
54 | | |
55 | | GNUC_INLINE static inline uint32_t |
56 | | rotl (uint32_t x, |
57 | | int8_t r) |
58 | 0 | { |
59 | 0 | return (x << r) | (x >> (32 - r)); |
60 | 0 | } |
61 | | |
62 | | /* |
63 | | * Finalization mix - force all bits of a hash block to avalanche |
64 | | */ |
65 | | |
66 | | GNUC_INLINE static inline uint32_t |
67 | | fmix (uint32_t h) |
68 | 0 | { |
69 | 0 | h ^= h >> 16; |
70 | 0 | h *= 0x85ebca6b; |
71 | 0 | h ^= h >> 13; |
72 | 0 | h *= 0xc2b2ae35; |
73 | 0 | h ^= h >> 16; |
74 | |
|
75 | 0 | return h; |
76 | 0 | } |
77 | | |
78 | | |
79 | | void |
80 | | p11_hash_murmur3 (void *hash, |
81 | | const void *input, |
82 | | size_t len, |
83 | | ...) |
84 | 0 | { |
85 | 0 | uint8_t overflow[4]; |
86 | 0 | const uint8_t *data; |
87 | 0 | va_list va; |
88 | 0 | uint32_t h1; |
89 | 0 | uint32_t k1; |
90 | 0 | uint32_t c1; |
91 | 0 | uint32_t c2; |
92 | |
|
93 | 0 | h1 = 42; /* arbitrary choice of seed */ |
94 | 0 | c1 = 0xcc9e2d51; |
95 | 0 | c2 = 0x1b873593; |
96 | 0 | data = input; |
97 | | |
98 | | /* body */ |
99 | | |
100 | | /* Mix 4 bytes at a time into the hash */ |
101 | 0 | va_start (va, len); |
102 | 0 | for (;;) { |
103 | 0 | if (len >= 4) { |
104 | 0 | memcpy (&k1, data, 4); |
105 | 0 | data += 4; |
106 | 0 | len -= 4; |
107 | |
|
108 | 0 | } else { |
109 | 0 | size_t num = len; |
110 | 0 | memcpy (overflow, data, len); |
111 | |
|
112 | 0 | while (num < 4) { |
113 | 0 | size_t part; |
114 | |
|
115 | 0 | data = va_arg (va, const void *); |
116 | 0 | if (!data) |
117 | 0 | break; |
118 | | |
119 | | /* Combine uint32 from old and new */ |
120 | 0 | len = va_arg (va, size_t); |
121 | 0 | part = 4 - num; |
122 | 0 | if (part > len) |
123 | 0 | part = len; |
124 | 0 | memcpy (overflow + num, data, part); |
125 | 0 | data += part; |
126 | 0 | len -= part; |
127 | 0 | num += part; |
128 | 0 | } |
129 | |
|
130 | 0 | if (num < 4) { |
131 | 0 | len = num; |
132 | 0 | break; |
133 | 0 | } |
134 | | |
135 | 0 | memcpy (&k1, overflow, 4); |
136 | 0 | } |
137 | | |
138 | 0 | k1 *= c1; |
139 | 0 | k1 = rotl (k1, 15); |
140 | 0 | k1 *= c2; |
141 | |
|
142 | 0 | h1 ^= k1; |
143 | 0 | h1 = rotl (h1, 13); |
144 | 0 | h1 = h1 * 5 + 0xe6546b64; |
145 | 0 | } |
146 | 0 | va_end (va); |
147 | | |
148 | | /* tail */ |
149 | |
|
150 | 0 | k1 = 0; |
151 | |
|
152 | 0 | switch (len) { |
153 | 0 | case 3: |
154 | 0 | k1 ^= overflow[2] << 16; |
155 | 0 | case 2: |
156 | 0 | k1 ^= overflow[1] << 8; |
157 | 0 | case 1: |
158 | 0 | k1 ^= overflow[0]; |
159 | 0 | k1 *= c1; |
160 | 0 | k1 = rotl (k1, 15); |
161 | 0 | k1 *= c2; |
162 | 0 | h1 ^= k1; |
163 | 0 | default: |
164 | 0 | break; |
165 | 0 | } |
166 | | |
167 | | /* finalization */ |
168 | | |
169 | 0 | h1 ^= len; |
170 | 0 | h1 = fmix(h1); |
171 | |
|
172 | 0 | assert (sizeof (h1) == P11_HASH_MURMUR3_LEN); |
173 | 0 | memcpy (hash, &h1, sizeof (h1)); |
174 | 0 | } |