File Coverage

_tiger.c
Criterion Covered Total %
statement 44 62 70.9
branch 10 20 50.0
condition n/a
subroutine n/a
pod n/a
total 54 82 65.8


line stmt bran cond sub pod time code
1             /* tiger.c - an implementation of Tiger Hash Function
2             * based on the article by
3             * Ross Anderson and Eli Biham "Tiger: A Fast New Hash Function".
4             *
5             * Copyright (c) 2007, Aleksey Kravchenko
6             *
7             * Permission to use, copy, modify, and/or distribute this software for any
8             * purpose with or without fee is hereby granted.
9             *
10             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11             * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12             * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14             * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15             * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16             * PERFORMANCE OF THIS SOFTWARE.
17             */
18              
19             #include
20             #include "byte_order.h"
21             #include "tiger.h"
22              
23             #ifdef NO_TIGER2
24             # define TIGER2_FLAG I64(0)
25             #else
26             # define TIGER2_FLAG I64(0x8000000000000000)
27             #endif /* NO_TIGER2 */
28              
29             #define LENGTH_MASK (~TIGER2_FLAG)
30             #define INITIALIZE_TIGER_STATE(state) \
31             state[0] = I64(0x0123456789ABCDEF); \
32             state[1] = I64(0xFEDCBA9876543210); \
33             state[2] = I64(0xF096A5B4C3B2E187);
34              
35             /**
36             * Initialize Tiger context before calculating hash.
37             *
38             * @param ctx context to initialize
39             */
40 6           void rhash_tiger_init(tiger_ctx* ctx)
41             {
42 6           ctx->length = 0;
43 6           INITIALIZE_TIGER_STATE(ctx->hash);
44 6           }
45              
46             #ifndef NO_TIGER2
47             /**
48             * Initialize Tiger2 context before calculating hash.
49             *
50             * @param ctx context to initialize
51             */
52 0           void rhash_tiger2_init(tiger_ctx* ctx)
53             {
54 0           ctx->length = TIGER2_FLAG;
55 0           INITIALIZE_TIGER_STATE(ctx->hash);
56 0           }
57             #endif /* NO_TIGER2 */
58              
59             /* lookup tables */
60             extern uint64_t rhash_tiger_sboxes[4][256];
61             #define t1 rhash_tiger_sboxes[0]
62             #define t2 rhash_tiger_sboxes[1]
63             #define t3 rhash_tiger_sboxes[2]
64             #define t4 rhash_tiger_sboxes[3]
65              
66             #ifdef CPU_X64 /* for x86-64 */
67             #define round(a,b,c,x,mul) \
68             c ^= x; \
69             a -= t1[(uint8_t)(c)] ^ \
70             t2[(uint8_t)((c) >> (2 * 8))] ^ \
71             t3[(uint8_t)((c) >> (4 * 8))] ^ \
72             t4[(uint8_t)((c) >> (6 * 8))] ; \
73             b += t4[(uint8_t)((c) >> (1 * 8))] ^ \
74             t3[(uint8_t)((c) >> (3 * 8))] ^ \
75             t2[(uint8_t)((c) >> (5 * 8))] ^ \
76             t1[(uint8_t)((c) >> (7 * 8))]; \
77             b *= mul;
78              
79             #else /* for IA32 */
80              
81             #define round(a,b,c,x,mul) \
82             c ^= x; \
83             a -= t1[(uint8_t)(c)] ^ \
84             t2[(uint8_t)(((uint32_t)(c)) >> (2 * 8))] ^ \
85             t3[(uint8_t)((c) >> (4 * 8))] ^ \
86             t4[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (2 * 8))] ; \
87             b += t4[(uint8_t)(((uint32_t)(c)) >> (1 * 8))] ^ \
88             t3[(uint8_t)(((uint32_t)(c)) >> (3 * 8))] ^ \
89             t2[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (1 * 8))] ^ \
90             t1[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (3 * 8))]; \
91             b *= mul;
92             #endif /* CPU_X64 */
93              
94             #define pass(a,b,c,mul) \
95             round(a,b,c,x0,mul) \
96             round(b,c,a,x1,mul) \
97             round(c,a,b,x2,mul) \
98             round(a,b,c,x3,mul) \
99             round(b,c,a,x4,mul) \
100             round(c,a,b,x5,mul) \
101             round(a,b,c,x6,mul) \
102             round(b,c,a,x7,mul)
103              
104             #define key_schedule { \
105             x0 -= x7 ^ I64(0xA5A5A5A5A5A5A5A5); \
106             x1 ^= x0; \
107             x2 += x1; \
108             x3 -= x2 ^ ((~x1)<<19); \
109             x4 ^= x3; \
110             x5 += x4; \
111             x6 -= x5 ^ ((~x4)>>23); \
112             x7 ^= x6; \
113             x0 += x7; \
114             x1 -= x0 ^ ((~x7)<<19); \
115             x2 ^= x1; \
116             x3 += x2; \
117             x4 -= x3 ^ ((~x2)>>23); \
118             x5 ^= x4; \
119             x6 += x5; \
120             x7 -= x6 ^ I64(0x0123456789ABCDEF); \
121             }
122              
123             /**
124             * The core transformation. Process a 512-bit block.
125             *
126             * @param state the algorithm state
127             * @param block the message block to process
128             */
129 6           static void rhash_tiger_process_block(uint64_t state[3], uint64_t* block)
130             {
131             /* Optimized for GCC IA32.
132             The order of declarations is important for compiler. */
133             uint64_t a, b, c;
134             uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
135             #ifndef CPU_X64
136             uint64_t tmp;
137             char i;
138             #endif
139              
140 6           x0 = le2me_64(block[0]); x1 = le2me_64(block[1]);
141 6           x2 = le2me_64(block[2]); x3 = le2me_64(block[3]);
142 6           x4 = le2me_64(block[4]); x5 = le2me_64(block[5]);
143 6           x6 = le2me_64(block[6]); x7 = le2me_64(block[7]);
144              
145 6           a = state[0];
146 6           b = state[1];
147 6           c = state[2];
148              
149             /* passes and key shedules */
150             #ifndef CPU_X64
151             for (i = 0; i < 3; i++) {
152             if (i != 0) key_schedule;
153             pass(a, b, c, (i == 0 ? 5 : i == 1 ? 7 : 9));
154             tmp = a;
155             a = c;
156             c = b;
157             b = tmp;
158             }
159             #else
160 6           pass(a, b, c, 5);
161 6           key_schedule;
162 6           pass(c, a, b, 7);
163 6           key_schedule;
164 6           pass(b, c, a, 9);
165             #endif
166              
167             /* feedforward operation */
168 6           state[0] = a ^ state[0];
169 6           state[1] = b - state[1];
170 6           state[2] = c + state[2];
171 6           }
172              
173             /**
174             * Calculate message hash.
175             * Can be called repeatedly with chunks of the message to be hashed.
176             *
177             * @param ctx the algorithm context containing current hashing state
178             * @param msg message chunk
179             * @param size length of the message chunk
180             */
181 5           void rhash_tiger_update(tiger_ctx* ctx, const unsigned char* msg, size_t size)
182             {
183 5           size_t index = (size_t)ctx->length & 63;
184 5           ctx->length += size;
185              
186             /* fill partial block */
187 5 100         if (index) {
188 3           size_t left = tiger_block_size - index;
189 3 50         if (size < left) {
190 3 50         if (size > 0)
191 3           memcpy(ctx->message + index, msg, size);
192 3           return;
193             } else {
194 0           memcpy(ctx->message + index, msg, left);
195 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)ctx->message);
196 0           msg += left;
197 0           size -= left;
198             }
199             }
200 2 50         while (size >= tiger_block_size) {
201 0 0         if (IS_ALIGNED_64(msg)) {
202             /* the most common case is processing of an already aligned message
203             without copying it */
204 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)msg);
205             } else {
206 0           memcpy(ctx->message, msg, tiger_block_size);
207 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)ctx->message);
208             }
209              
210 0           msg += tiger_block_size;
211 0           size -= tiger_block_size;
212             }
213 2 50         if (size) {
214             /* save leftovers */
215 2           memcpy(ctx->message, msg, size);
216             }
217             }
218              
219             /**
220             * Store calculated hash into the given array.
221             *
222             * @param ctx the algorithm context containing current hashing state
223             * @param result calculated hash in binary form
224             */
225 6           void rhash_tiger_final(tiger_ctx* ctx, unsigned char result[24])
226             {
227 6           unsigned index = (unsigned)ctx->length & 63;
228 6           uint64_t* msg64 = (uint64_t*)ctx->message;
229              
230             /* pad message and run for last block */
231              
232             /* append the byte 0x01 to the message */
233 6 50         ctx->message[index++] = (ctx->length & TIGER2_FLAG ? 0x80 : 0x01);
234              
235             /* if no room left in the message to store 64-bit message length */
236 6 50         if (index > 56) {
237             /* then fill the rest with zeros and process it */
238 0 0         while (index < 64) {
239 0           ctx->message[index++] = 0;
240             }
241 0           rhash_tiger_process_block(ctx->hash, msg64);
242 0           index = 0;
243             }
244 314 100         while (index < 56) {
245 308           ctx->message[index++] = 0;
246             }
247 6           msg64[7] = le2me_64((ctx->length & LENGTH_MASK) << 3);
248 6           rhash_tiger_process_block(ctx->hash, msg64);
249              
250             /* save result hash */
251 6           le64_copy(result, 0, &ctx->hash, 24);
252 6           }