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