1 /* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
2 /*======================================================================
3 Copyright (C) 2004,2005,2009,2011 Walter Doekes <walter+tthsum@wjd.nu>
4 This file is part of tthsum.
5
6 tthsum is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 tthsum is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with tthsum. If not, see <http://www.gnu.org/licenses/>.
18 ======================================================================*/
19 #include "thex.h"
20
21 #include "endian.h"
22 #include "read.h"
23 #include "tiger.h"
24 #include <stdio.h>
25 #include <string.h>
26
27 #ifdef USE_TEXTS
28 # include "texts.h"
29 #endif /* USE_TEXTS */
30
31 #define TWO_HASH_OCTETS (2*3*8)
32
33
get_progress_mask(uint64_t filesize)34 static unsigned get_progress_mask(uint64_t filesize) {
35 unsigned bit = 2;
36 for (filesize >>= 18; filesize != 0; filesize >>= 1)
37 bit <<= 1;
38 return bit - 1;
39 }
40
thex_tiger_root(struct rofile * stream,uint64_t * result,void (* progress_func)(uint64_t,uint64_t))41 int thex_tiger_root(struct rofile* stream, uint64_t* result,
42 void (*progress_func)(uint64_t,uint64_t)) {
43 int ret;
44 unsigned progress_mask = 0x7fff;
45 /* Read data */
46 unsigned blocksize;
47 uint64_t filesize;
48 /* Tiger data */
49 uint64_t data[128]; /* with 128, we have enough room for a 2^137B file */
50 uint64_t leafcount = 0;
51 unsigned pos = 0;
52
53 /* Assert that the blocksize is a multiple of 1024 */
54 rofinfo(&blocksize, &filesize, stream);
55 if (blocksize % 1024 != 0) {
56 #ifdef USE_TEXTS
57 set_error("thex_tiger_root", THEX_INVALID_BLOCK_SIZE);
58 #endif /* USE_TEXTS */
59 return -1;
60 }
61
62 /* Get number progress_func mask to check against leafcount */
63 if (filesize != (uint64_t)-1)
64 progress_mask = get_progress_mask(filesize);
65
66 #if 0
67 /* 4gb == 2^42, requires 33 blocks */
68 if (filesize >= 1024)
69 tthblocks = (int)ceil(log((double)filesize / 1024.0) / log(2)) + 1;
70 else
71 tthblocks = 1;
72 printf("fs = %lli, tths = %u\r\n", filesize, tthblocks);
73 data = (uint64_t*)malloc(tthblocks * 3 * sizeof(uint64_t));
74 #endif
75
76 while (1) {
77 const char* p;
78 unsigned size;
79
80 /* Read block of data */
81 ret = rofread(&p, &size, stream);
82 if (ret <= 0)
83 break;
84
85 /* Iterate over our fetched block of data */
86 while (1) {
87 unsigned i;
88 tiger_bp(0x00, p, size < 1024 ? size : 1024, data + pos);
89 /* Print progress */
90 if (progress_func && ((unsigned)leafcount & progress_mask) == 0) {
91 progress_func(leafcount * 1024, filesize);
92 }
93 /* Merge backwards */
94 ++leafcount;
95 for (i = 2; (unsigned)leafcount % i == 0; i *= 2) {
96 #if BYTE_ORDER == BIG_ENDIAN
97 uint8_t temp[TWO_HASH_OCTETS];
98 int j;
99 pos -= 3;
100 for (j = 0; j < TWO_HASH_OCTETS; ++j)
101 temp[j ^ 7] = ((uint8_t*)(data + pos))[j];
102 tiger_bp(0x01, &temp[0], TWO_HASH_OCTETS, data + pos);
103 #else /* BYTE_ORDER != BIG_ENDIAN */
104 uint64_t temp[3];
105 pos -= 3;
106 tiger_bp(0x01, data + pos, TWO_HASH_OCTETS, temp);
107 data[pos] = temp[0];
108 data[pos + 1] = temp[1];
109 data[pos + 2] = temp[2];
110 #endif /* BYTE_ORDER != BIG_ENDIAN */
111 }
112 pos += 3;
113
114 if (size <= 1024)
115 break;
116
117 size -= 1024;
118 p += 1024;
119 }
120 }
121
122 if (progress_func)
123 progress_func(leafcount, filesize);
124
125 /* Did some error occur? */
126 if (ret == -1)
127 return ret;
128
129 if (pos == 0) {
130 /* Nothing written, create the single leaf root */
131 tiger_bp(0x00, (const void*)0, 0, data);
132 } else {
133 /* Merge backwards */
134 pos -= 3;
135 while (pos != 0) {
136 #if BYTE_ORDER == BIG_ENDIAN
137 uint8_t temp[TWO_HASH_OCTETS];
138 int j;
139 pos -= 3;
140 for (j = 0; j < TWO_HASH_OCTETS; ++j)
141 temp[j ^ 7] = ((const uint8_t*)(data + pos))[j];
142 tiger_bp(0x01, &temp[0], TWO_HASH_OCTETS, data + pos);
143 #else /* BYTE_ORDER != BIG_ENDIAN */
144 uint64_t temp[3];
145 pos -= 3;
146 tiger_bp(0x01, data + pos, TWO_HASH_OCTETS, temp);
147 data[pos] = temp[0];
148 data[pos + 1] = temp[1];
149 data[pos + 2] = temp[2];
150 #endif /* BYTE_ORDER != BIG_ENDIAN */
151 }
152 }
153
154 /* Done, return success */
155 result[0] = data[0];
156 result[1] = data[1];
157 result[2] = data[2];
158 return 0;
159 }
160