File Coverage

_tiger.c
Criterion Covered Total %
statement 46 60 76.6
branch 9 18 50.0
condition n/a
subroutine n/a
pod n/a
total 55 78 70.5


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: 2007-2012 Aleksey Kravchenko
6             *
7             * Permission is hereby granted, free of charge, to any person obtaining a
8             * copy of this software and associated documentation files (the "Software"),
9             * to deal in the Software without restriction, including without limitation
10             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11             * and/or sell copies of the Software, and to permit persons to whom the
12             * Software is furnished to do so.
13             *
14             * This program is distributed in the hope that it will be useful, but
15             * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16             * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
17             */
18              
19             #include
20             #include "byte_order.h"
21             #include "tiger.h"
22              
23             /**
24             * Initialize algorithm context before calculaing hash.
25             *
26             * @param ctx context to initialize
27             */
28 6           void rhash_tiger_init(tiger_ctx *ctx)
29             {
30 6           ctx->length = 0;
31 6           ctx->tiger2 = 0;
32              
33             /* initialize algorithm state */
34 6           ctx->hash[0] = I64(0x0123456789ABCDEF);
35 6           ctx->hash[1] = I64(0xFEDCBA9876543210);
36 6           ctx->hash[2] = I64(0xF096A5B4C3B2E187);
37 6           }
38              
39             /* lookup tables */
40             extern uint64_t rhash_tiger_sboxes[4][256];
41             #define t1 rhash_tiger_sboxes[0]
42             #define t2 rhash_tiger_sboxes[1]
43             #define t3 rhash_tiger_sboxes[2]
44             #define t4 rhash_tiger_sboxes[3]
45              
46             #ifdef CPU_X64 /* for x86-64 */
47             #define round(a,b,c,x,mul) \
48             c ^= x; \
49             a -= t1[(uint8_t)(c)] ^ \
50             t2[(uint8_t)((c) >> (2 * 8))] ^ \
51             t3[(uint8_t)((c) >> (4 * 8))] ^ \
52             t4[(uint8_t)((c) >> (6 * 8))] ; \
53             b += t4[(uint8_t)((c) >> (1 * 8))] ^ \
54             t3[(uint8_t)((c) >> (3 * 8))] ^ \
55             t2[(uint8_t)((c) >> (5 * 8))] ^ \
56             t1[(uint8_t)((c) >> (7 * 8))]; \
57             b *= mul;
58              
59             #else /* for IA32 */
60              
61             #define round(a,b,c,x,mul) \
62             c ^= x; \
63             a -= t1[(uint8_t)(c)] ^ \
64             t2[(uint8_t)(((uint32_t)(c)) >> (2 * 8))] ^ \
65             t3[(uint8_t)((c) >> (4 * 8))] ^ \
66             t4[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (2 * 8))] ; \
67             b += t4[(uint8_t)(((uint32_t)(c)) >> (1 * 8))] ^ \
68             t3[(uint8_t)(((uint32_t)(c)) >> (3 * 8))] ^ \
69             t2[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (1 * 8))] ^ \
70             t1[(uint8_t)(((uint32_t)((c) >> (4 * 8))) >> (3 * 8))]; \
71             b *= mul;
72             #endif /* CPU_X64 */
73              
74             #define pass(a,b,c,mul) \
75             round(a,b,c,x0,mul) \
76             round(b,c,a,x1,mul) \
77             round(c,a,b,x2,mul) \
78             round(a,b,c,x3,mul) \
79             round(b,c,a,x4,mul) \
80             round(c,a,b,x5,mul) \
81             round(a,b,c,x6,mul) \
82             round(b,c,a,x7,mul)
83              
84             #define key_schedule { \
85             x0 -= x7 ^ I64(0xA5A5A5A5A5A5A5A5); \
86             x1 ^= x0; \
87             x2 += x1; \
88             x3 -= x2 ^ ((~x1)<<19); \
89             x4 ^= x3; \
90             x5 += x4; \
91             x6 -= x5 ^ ((~x4)>>23); \
92             x7 ^= x6; \
93             x0 += x7; \
94             x1 -= x0 ^ ((~x7)<<19); \
95             x2 ^= x1; \
96             x3 += x2; \
97             x4 -= x3 ^ ((~x2)>>23); \
98             x5 ^= x4; \
99             x6 += x5; \
100             x7 -= x6 ^ I64(0x0123456789ABCDEF); \
101             }
102              
103             /**
104             * The core transformation. Process a 512-bit block.
105             *
106             * @param state the algorithm state
107             * @param block the message block to process
108             */
109 6           static void rhash_tiger_process_block(uint64_t state[3], uint64_t* block)
110             {
111             /* Optimized for GCC IA32.
112             The order of declarations is important for compiler. */
113             uint64_t a, b, c;
114             uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
115             #ifndef CPU_X64
116             uint64_t tmp;
117             char i;
118             #endif
119              
120 6           x0 = le2me_64(block[0]); x1 = le2me_64(block[1]);
121 6           x2 = le2me_64(block[2]); x3 = le2me_64(block[3]);
122 6           x4 = le2me_64(block[4]); x5 = le2me_64(block[5]);
123 6           x6 = le2me_64(block[6]); x7 = le2me_64(block[7]);
124              
125 6           a = state[0];
126 6           b = state[1];
127 6           c = state[2];
128              
129             /* passes and key shedules */
130             #ifndef CPU_X64
131             for (i = 0; i < 3; i++) {
132             if (i != 0) key_schedule;
133             pass(a, b, c, (i == 0 ? 5 : i == 1 ? 7 : 9));
134             tmp = a;
135             a = c;
136             c = b;
137             b = tmp;
138             }
139             #else
140 6           pass(a, b, c, 5);
141 6           key_schedule;
142 6           pass(c, a, b, 7);
143 6           key_schedule;
144 6           pass(b, c, a, 9);
145             #endif
146              
147             /* feedforward operation */
148 6           state[0] = a ^ state[0];
149 6           state[1] = b - state[1];
150 6           state[2] = c + state[2];
151 6           }
152              
153             /**
154             * Calculate message hash.
155             * Can be called repeatedly with chunks of the message to be hashed.
156             *
157             * @param ctx the algorithm context containing current hashing state
158             * @param msg message chunk
159             * @param size length of the message chunk
160             */
161 5           void rhash_tiger_update(tiger_ctx *ctx, const unsigned char* msg, size_t size)
162             {
163 5           size_t index = (size_t)ctx->length & 63;
164 5           ctx->length += size;
165              
166             /* fill partial block */
167 5 100         if (index) {
168 3           size_t left = tiger_block_size - index;
169 3 50         if (size < left) {
170 3           memcpy(ctx->message + index, msg, size);
171 3           return;
172             } else {
173 0           memcpy(ctx->message + index, msg, left);
174 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)ctx->message);
175 0           msg += left;
176 0           size -= left;
177             }
178             }
179 2 50         while (size >= tiger_block_size) {
180 0 0         if (IS_ALIGNED_64(msg)) {
181             /* the most common case is processing of an already aligned message
182             without copying it */
183 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)msg);
184             } else {
185 0           memcpy(ctx->message, msg, tiger_block_size);
186 0           rhash_tiger_process_block(ctx->hash, (uint64_t*)ctx->message);
187             }
188              
189 0           msg += tiger_block_size;
190 0           size -= tiger_block_size;
191             }
192 2 50         if (size) {
193             /* save leftovers */
194 2           memcpy(ctx->message, msg, size);
195             }
196             }
197              
198             /**
199             * Store calculated hash into the given array.
200             *
201             * @param ctx the algorithm context containing current hashing state
202             * @param result calculated hash in binary form
203             */
204 6           void rhash_tiger_final(tiger_ctx *ctx, unsigned char result[24])
205             {
206 6           unsigned index = (unsigned)ctx->length & 63;
207 6           uint64_t* msg64 = (uint64_t*)ctx->message;
208              
209             /* pad message and run for last block */
210              
211             /* append the byte 0x01 to the message */
212 6 50         ctx->message[index++] = (ctx->tiger2 ? 0x80 : 0x01);
213              
214             /* if no room left in the message to store 64-bit message length */
215 6 50         if (index > 56) {
216             /* then fill the rest with zeros and process it */
217 0 0         while (index < 64) {
218 0           ctx->message[index++] = 0;
219             }
220 0           rhash_tiger_process_block(ctx->hash, msg64);
221 0           index = 0;
222             }
223 314 100         while (index < 56) {
224 308           ctx->message[index++] = 0;
225             }
226 6           msg64[7] = le2me_64(ctx->length << 3);
227 6           rhash_tiger_process_block(ctx->hash, msg64);
228              
229             /* save result hash */
230 6           le64_copy(result, 0, &ctx->hash, 24);
231 6           }