ethash 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,202 @@
1
+ /*
2
+ This file is part of ethash.
3
+
4
+ ethash is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ ethash is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with ethash. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /** @file io.h
18
+ * @author Lefteris Karapetsas <lefteris@ethdev.com>
19
+ * @date 2015
20
+ */
21
+ #pragma once
22
+ #include <stdlib.h>
23
+ #include <stdint.h>
24
+ #include <stdbool.h>
25
+ #include <stdio.h>
26
+ #ifdef __cplusplus
27
+ #define __STDC_FORMAT_MACROS 1
28
+ #endif
29
+ #include <inttypes.h>
30
+ #include "endian.h"
31
+ #include "ethash.h"
32
+
33
+ #ifdef __cplusplus
34
+ extern "C" {
35
+ #endif
36
+ // Maximum size for mutable part of DAG file name
37
+ // 6 is for "full-R", the suffix of the filename
38
+ // 10 is for maximum number of digits of a uint32_t (for REVISION)
39
+ // 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
40
+ // the seedhash and last 1 is for the null terminating character
41
+ // Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
42
+ #define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
43
+ /// Possible return values of @see ethash_io_prepare
44
+ enum ethash_io_rc {
45
+ ETHASH_IO_FAIL = 0, ///< There has been an IO failure
46
+ ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
47
+ ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
48
+ ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
49
+ };
50
+
51
+ // small hack for windows. I don't feel I should use va_args and forward just
52
+ // to have this one function properly cross-platform abstracted
53
+ #if defined(_WIN32) && !defined(__GNUC__)
54
+ #define snprintf(...) sprintf_s(__VA_ARGS__)
55
+ #endif
56
+
57
+ /**
58
+ * Logs a critical error in important parts of ethash. Should mostly help
59
+ * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
60
+ * ethash_full_t
61
+ */
62
+ #ifdef ETHASH_PRINT_CRITICAL_OUTPUT
63
+ #define ETHASH_CRITICAL(...) \
64
+ do \
65
+ { \
66
+ printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
67
+ printf("\n"); \
68
+ fflush(stdout); \
69
+ } while (0)
70
+ #else
71
+ #define ETHASH_CRITICAL(...)
72
+ #endif
73
+
74
+ /**
75
+ * Prepares io for ethash
76
+ *
77
+ * Create the DAG directory and the DAG file if they don't exist.
78
+ *
79
+ * @param[in] dirname A null terminated c-string of the path of the ethash
80
+ * data directory. If it does not exist it's created.
81
+ * @param[in] seedhash The seedhash of the current block number, used in the
82
+ * naming of the file as can be seen from the spec at:
83
+ * https://github.com/ethereum/wiki/wiki/Ethash-DAG
84
+ * @param[out] output_file If there was no failure then this will point to an open
85
+ * file descriptor. User is responsible for closing it.
86
+ * In the case of memo match then the file is open on read
87
+ * mode, while on the case of mismatch a new file is created
88
+ * on write mode
89
+ * @param[in] file_size The size that the DAG file should have on disk
90
+ * @param[out] force_create If true then there is no check to see if the file
91
+ * already exists
92
+ * @return For possible return values @see enum ethash_io_rc
93
+ */
94
+ enum ethash_io_rc ethash_io_prepare(
95
+ char const* dirname,
96
+ ethash_h256_t const seedhash,
97
+ FILE** output_file,
98
+ uint64_t file_size,
99
+ bool force_create
100
+ );
101
+
102
+ /**
103
+ * An fopen wrapper for no-warnings crossplatform fopen.
104
+ *
105
+ * Msvc compiler considers fopen to be insecure and suggests to use their
106
+ * alternative. This is a wrapper for this alternative. Another way is to
107
+ * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
108
+ * not sound like a good idea.
109
+ *
110
+ * @param file_name The path to the file to open
111
+ * @param mode Opening mode. Check fopen()
112
+ * @return The FILE* or NULL in failure
113
+ */
114
+ FILE* ethash_fopen(char const* file_name, char const* mode);
115
+
116
+ /**
117
+ * An strncat wrapper for no-warnings crossplatform strncat.
118
+ *
119
+ * Msvc compiler considers strncat to be insecure and suggests to use their
120
+ * alternative. This is a wrapper for this alternative. Another way is to
121
+ * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
122
+ * not sound like a good idea.
123
+ *
124
+ * @param des Destination buffer
125
+ * @param dest_size Maximum size of the destination buffer. This is the
126
+ * extra argument for the MSVC secure strncat
127
+ * @param src Souce buffer
128
+ * @param count Number of bytes to copy from source
129
+ * @return If all is well returns the dest buffer. If there is an
130
+ * error returns NULL
131
+ */
132
+ char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count);
133
+
134
+ /**
135
+ * A cross-platform mkdir wrapper to create a directory or assert it's there
136
+ *
137
+ * @param dirname The full path of the directory to create
138
+ * @return true if the directory was created or if it already
139
+ * existed
140
+ */
141
+ bool ethash_mkdir(char const* dirname);
142
+
143
+ /**
144
+ * Get a file's size
145
+ *
146
+ * @param[in] f The open file stream whose size to get
147
+ * @param[out] size Pass a size_t by reference to contain the file size
148
+ * @return true in success and false if there was a failure
149
+ */
150
+ bool ethash_file_size(FILE* f, size_t* ret_size);
151
+
152
+ /**
153
+ * Get a file descriptor number from a FILE stream
154
+ *
155
+ * @param f The file stream whose fd to get
156
+ * @return Platform specific fd handler
157
+ */
158
+ int ethash_fileno(FILE* f);
159
+
160
+ /**
161
+ * Create the filename for the DAG.
162
+ *
163
+ * @param dirname The directory name in which the DAG file should reside
164
+ * If it does not end with a directory separator it is appended.
165
+ * @param filename The actual name of the file
166
+ * @param filename_length The length of the filename in bytes
167
+ * @return A char* containing the full name. User must deallocate.
168
+ */
169
+ char* ethash_io_create_filename(
170
+ char const* dirname,
171
+ char const* filename,
172
+ size_t filename_length
173
+ );
174
+
175
+ /**
176
+ * Gets the default directory name for the DAG depending on the system
177
+ *
178
+ * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG
179
+ *
180
+ * @param[out] strbuf A string buffer of sufficient size to keep the
181
+ * null termninated string of the directory name
182
+ * @param[in] buffsize Size of @a strbuf in bytes
183
+ * @return true for success and false otherwise
184
+ */
185
+ bool ethash_get_default_dirname(char* strbuf, size_t buffsize);
186
+
187
+ static inline bool ethash_io_mutable_name(
188
+ uint32_t revision,
189
+ ethash_h256_t const* seed_hash,
190
+ char* output
191
+ )
192
+ {
193
+ uint64_t hash = *((uint64_t*)seed_hash);
194
+ #if LITTLE_ENDIAN == BYTE_ORDER
195
+ hash = ethash_swap_u64(hash);
196
+ #endif
197
+ return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0;
198
+ }
199
+
200
+ #ifdef __cplusplus
201
+ }
202
+ #endif
@@ -0,0 +1,47 @@
1
+ /*
2
+ This file is part of ethash.
3
+
4
+ ethash is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ ethash is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with ethash. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /** @file mmap.h
18
+ * @author Lefteris Karapetsas <lefteris@ethdev.com>
19
+ * @date 2015
20
+ */
21
+ #pragma once
22
+ #if defined(__MINGW32__) || defined(_WIN32)
23
+ #include <sys/types.h>
24
+
25
+ #define PROT_READ 0x1
26
+ #define PROT_WRITE 0x2
27
+ /* This flag is only available in WinXP+ */
28
+ #ifdef FILE_MAP_EXECUTE
29
+ #define PROT_EXEC 0x4
30
+ #else
31
+ #define PROT_EXEC 0x0
32
+ #define FILE_MAP_EXECUTE 0
33
+ #endif
34
+
35
+ #define MAP_SHARED 0x01
36
+ #define MAP_PRIVATE 0x02
37
+ #define MAP_ANONYMOUS 0x20
38
+ #define MAP_ANON MAP_ANONYMOUS
39
+ #define MAP_FAILED ((void *) -1)
40
+
41
+ void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
42
+ void munmap(void* addr, size_t length);
43
+ #else // posix, yay! ^_^
44
+ #include <sys/mman.h>
45
+ #endif
46
+
47
+
@@ -0,0 +1,31 @@
1
+ #pragma once
2
+
3
+ #ifdef __cplusplus
4
+ extern "C" {
5
+ #endif
6
+
7
+ #include "compiler.h"
8
+ #include <stdint.h>
9
+ #include <stdlib.h>
10
+
11
+ struct ethash_h256;
12
+
13
+ #define decsha3(bits) \
14
+ int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t);
15
+
16
+ decsha3(256)
17
+ decsha3(512)
18
+
19
+ static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size)
20
+ {
21
+ sha3_256((uint8_t*)ret, 32, data, size);
22
+ }
23
+
24
+ static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size)
25
+ {
26
+ sha3_512(ret, 64, data, size);
27
+ }
28
+
29
+ #ifdef __cplusplus
30
+ }
31
+ #endif
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+
3
+ #include "compiler.h"
4
+ #include <stdint.h>
5
+ #include <stdlib.h>
6
+
7
+ #ifdef __cplusplus
8
+ extern "C" {
9
+ #endif
10
+
11
+ struct ethash_h256;
12
+
13
+ void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size);
14
+ void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size);
15
+
16
+ #ifdef __cplusplus
17
+ }
18
+ #endif
@@ -0,0 +1,47 @@
1
+ /*
2
+ This file is part of ethash.
3
+
4
+ ethash is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ ethash is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with ethash. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /** @file util.h
18
+ * @author Tim Hughes <tim@twistedfury.com>
19
+ * @date 2015
20
+ */
21
+ #pragma once
22
+ #include <stdint.h>
23
+ #include "compiler.h"
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ #ifdef _MSC_VER
30
+ void debugf(char const* str, ...);
31
+ #else
32
+ #define debugf printf
33
+ #endif
34
+
35
+ static inline uint32_t min_u32(uint32_t a, uint32_t b)
36
+ {
37
+ return a < b ? a : b;
38
+ }
39
+
40
+ static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_)
41
+ {
42
+ return x < min_ ? min_ : (x > max_ ? max_ : x);
43
+ }
44
+
45
+ #ifdef __cplusplus
46
+ }
47
+ #endif
@@ -0,0 +1,508 @@
1
+ /*
2
+ This file is part of ethash.
3
+
4
+ ethash is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ ethash is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ /** @file internal.c
18
+ * @author Tim Hughes <tim@twistedfury.com>
19
+ * @author Matthew Wampler-Doty
20
+ * @date 2015
21
+ */
22
+
23
+ #include <assert.h>
24
+ #include <inttypes.h>
25
+ #include <stddef.h>
26
+ #include <errno.h>
27
+ #include <math.h>
28
+
29
+ #include "headers/mmap.h"
30
+ #include "headers/ethash.h"
31
+ #include "headers/fnv.h"
32
+ #include "headers/endian.h"
33
+ #include "headers/internal.h"
34
+ #include "headers/data_sizes.h"
35
+ #include "headers/io.h"
36
+
37
+ #ifdef WITH_CRYPTOPP
38
+
39
+ #include "headers/sha3_cryptopp.h"
40
+
41
+ #else
42
+ #include "headers/sha3.h"
43
+ #endif // WITH_CRYPTOPP
44
+
45
+ uint64_t ethash_get_datasize(uint64_t const block_number)
46
+ {
47
+ assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
48
+ return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
49
+ }
50
+
51
+ uint64_t ethash_get_cachesize(uint64_t const block_number)
52
+ {
53
+ assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
54
+ return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
55
+ }
56
+
57
+ // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
58
+ // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
59
+ // SeqMemoHash(s, R, N)
60
+ bool static ethash_compute_cache_nodes(
61
+ node* const nodes,
62
+ uint64_t cache_size,
63
+ ethash_h256_t const* seed
64
+ )
65
+ {
66
+ if (cache_size % sizeof(node) != 0) {
67
+ return false;
68
+ }
69
+ uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node));
70
+
71
+ SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
72
+
73
+ for (uint32_t i = 1; i != num_nodes; ++i) {
74
+ SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
75
+ }
76
+
77
+ for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
78
+ for (uint32_t i = 0; i != num_nodes; i++) {
79
+ uint32_t const idx = nodes[i].words[0] % num_nodes;
80
+ node data;
81
+ data = nodes[(num_nodes - 1 + i) % num_nodes];
82
+ for (uint32_t w = 0; w != NODE_WORDS; ++w) {
83
+ data.words[w] ^= nodes[idx].words[w];
84
+ }
85
+ SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
86
+ }
87
+ }
88
+
89
+ // now perform endian conversion
90
+ fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
91
+ return true;
92
+ }
93
+
94
+ void ethash_calculate_dag_item(
95
+ node* const ret,
96
+ uint32_t node_index,
97
+ ethash_light_t const light
98
+ )
99
+ {
100
+ uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node));
101
+ node const* cache_nodes = (node const *) light->cache;
102
+ node const* init = &cache_nodes[node_index % num_parent_nodes];
103
+ memcpy(ret, init, sizeof(node));
104
+ ret->words[0] ^= node_index;
105
+ SHA3_512(ret->bytes, ret->bytes, sizeof(node));
106
+ #if defined(_M_X64) && ENABLE_SSE
107
+ __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
108
+ __m128i xmm0 = ret->xmm[0];
109
+ __m128i xmm1 = ret->xmm[1];
110
+ __m128i xmm2 = ret->xmm[2];
111
+ __m128i xmm3 = ret->xmm[3];
112
+ #endif
113
+
114
+ for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
115
+ uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes;
116
+ node const *parent = &cache_nodes[parent_index];
117
+
118
+ #if defined(_M_X64) && ENABLE_SSE
119
+ {
120
+ xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
121
+ xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
122
+ xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
123
+ xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
124
+ xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
125
+ xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
126
+ xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
127
+ xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
128
+
129
+ // have to write to ret as values are used to compute index
130
+ ret->xmm[0] = xmm0;
131
+ ret->xmm[1] = xmm1;
132
+ ret->xmm[2] = xmm2;
133
+ ret->xmm[3] = xmm3;
134
+ }
135
+ #else
136
+ {
137
+ for (unsigned w = 0; w != NODE_WORDS; ++w) {
138
+ ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
139
+ }
140
+ }
141
+ #endif
142
+ }
143
+ SHA3_512(ret->bytes, ret->bytes, sizeof(node));
144
+ }
145
+
146
+ bool ethash_compute_full_data(
147
+ void* mem,
148
+ uint64_t full_size,
149
+ ethash_light_t const light,
150
+ ethash_callback_t callback
151
+ )
152
+ {
153
+ if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
154
+ (full_size % sizeof(node)) != 0) {
155
+ return false;
156
+ }
157
+ uint32_t const max_n = (uint32_t)(full_size / sizeof(node));
158
+ node* full_nodes = mem;
159
+ double const progress_change = 1.0f / max_n;
160
+ double progress = 0.0f;
161
+ // now compute full nodes
162
+ for (uint32_t n = 0; n != max_n; ++n) {
163
+ if (callback &&
164
+ n % (max_n / 100) == 0 &&
165
+ callback((unsigned int)(ceil(progress * 100.0f))) != 0) {
166
+
167
+ return false;
168
+ }
169
+ progress += progress_change;
170
+ ethash_calculate_dag_item(&(full_nodes[n]), n, light);
171
+ }
172
+ return true;
173
+ }
174
+
175
+ static bool ethash_hash(
176
+ ethash_return_value_t* ret,
177
+ node const* full_nodes,
178
+ ethash_light_t const light,
179
+ uint64_t full_size,
180
+ ethash_h256_t const header_hash,
181
+ uint64_t const nonce
182
+ )
183
+ {
184
+ if (full_size % MIX_WORDS != 0) {
185
+ return false;
186
+ }
187
+
188
+ // pack hash and nonce together into first 40 bytes of s_mix
189
+ assert(sizeof(node) * 8 == 512);
190
+ node s_mix[MIX_NODES + 1];
191
+ memcpy(s_mix[0].bytes, &header_hash, 32);
192
+ fix_endian64(s_mix[0].double_words[4], nonce);
193
+
194
+ // compute sha3-512 hash and replicate across mix
195
+ SHA3_512(s_mix->bytes, s_mix->bytes, 40);
196
+ fix_endian_arr32(s_mix[0].words, 16);
197
+
198
+ node* const mix = s_mix + 1;
199
+ for (uint32_t w = 0; w != MIX_WORDS; ++w) {
200
+ mix->words[w] = s_mix[0].words[w % NODE_WORDS];
201
+ }
202
+
203
+ unsigned const page_size = sizeof(uint32_t) * MIX_WORDS;
204
+ unsigned const num_full_pages = (unsigned) (full_size / page_size);
205
+
206
+ for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) {
207
+ uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages;
208
+
209
+ for (unsigned n = 0; n != MIX_NODES; ++n) {
210
+ node const* dag_node;
211
+ if (full_nodes) {
212
+ dag_node = &full_nodes[MIX_NODES * index + n];
213
+ } else {
214
+ node tmp_node;
215
+ ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
216
+ dag_node = &tmp_node;
217
+ }
218
+
219
+ #if defined(_M_X64) && ENABLE_SSE
220
+ {
221
+ __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
222
+ __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
223
+ __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
224
+ __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
225
+ __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
226
+ mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
227
+ mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
228
+ mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
229
+ mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
230
+ }
231
+ #else
232
+ {
233
+ for (unsigned w = 0; w != NODE_WORDS; ++w) {
234
+ mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
235
+ }
236
+ }
237
+ #endif
238
+ }
239
+
240
+ }
241
+
242
+ // compress mix
243
+ for (uint32_t w = 0; w != MIX_WORDS; w += 4) {
244
+ uint32_t reduction = mix->words[w + 0];
245
+ reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
246
+ reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
247
+ reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
248
+ mix->words[w / 4] = reduction;
249
+ }
250
+
251
+ fix_endian_arr32(mix->words, MIX_WORDS / 4);
252
+ memcpy(&ret->mix_hash, mix->bytes, 32);
253
+ // final Keccak hash
254
+ SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
255
+ return true;
256
+ }
257
+
258
+ void ethash_quick_hash(
259
+ ethash_h256_t* return_hash,
260
+ ethash_h256_t const* header_hash,
261
+ uint64_t const nonce,
262
+ ethash_h256_t const* mix_hash
263
+ )
264
+ {
265
+ uint8_t buf[64 + 32];
266
+ memcpy(buf, header_hash, 32);
267
+ fix_endian64_same(nonce);
268
+ memcpy(&(buf[32]), &nonce, 8);
269
+ SHA3_512(buf, buf, 40);
270
+ memcpy(&(buf[64]), mix_hash, 32);
271
+ SHA3_256(return_hash, buf, 64 + 32);
272
+ }
273
+
274
+ ethash_h256_t ethash_get_seedhash(uint64_t block_number)
275
+ {
276
+ ethash_h256_t ret;
277
+ ethash_h256_reset(&ret);
278
+ uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH;
279
+ for (uint32_t i = 0; i < epochs; ++i)
280
+ SHA3_256(&ret, (uint8_t*)&ret, 32);
281
+ return ret;
282
+ }
283
+
284
+ bool ethash_quick_check_difficulty(
285
+ ethash_h256_t const* header_hash,
286
+ uint64_t const nonce,
287
+ ethash_h256_t const* mix_hash,
288
+ ethash_h256_t const* boundary
289
+ )
290
+ {
291
+
292
+ ethash_h256_t return_hash;
293
+ ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
294
+ return ethash_check_difficulty(&return_hash, boundary);
295
+ }
296
+
297
+ ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
298
+ {
299
+ struct ethash_light *ret;
300
+ ret = calloc(sizeof(*ret), 1);
301
+ if (!ret) {
302
+ return NULL;
303
+ }
304
+ ret->cache = malloc((size_t)cache_size);
305
+ if (!ret->cache) {
306
+ goto fail_free_light;
307
+ }
308
+ node* nodes = (node*)ret->cache;
309
+ if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) {
310
+ goto fail_free_cache_mem;
311
+ }
312
+ ret->cache_size = cache_size;
313
+ return ret;
314
+
315
+ fail_free_cache_mem:
316
+ free(ret->cache);
317
+ fail_free_light:
318
+ free(ret);
319
+ return NULL;
320
+ }
321
+
322
+ ethash_light_t ethash_light_new(uint64_t block_number)
323
+ {
324
+ ethash_h256_t seedhash = ethash_get_seedhash(block_number);
325
+ ethash_light_t ret;
326
+ ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash);
327
+ ret->block_number = block_number;
328
+ return ret;
329
+ }
330
+
331
+ void ethash_light_delete(ethash_light_t light)
332
+ {
333
+ if (light->cache) {
334
+ free(light->cache);
335
+ }
336
+ free(light);
337
+ }
338
+
339
+ ethash_return_value_t ethash_light_compute_internal(
340
+ ethash_light_t light,
341
+ uint64_t full_size,
342
+ ethash_h256_t const header_hash,
343
+ uint64_t nonce
344
+ )
345
+ {
346
+ ethash_return_value_t ret;
347
+ ret.success = true;
348
+ if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) {
349
+ ret.success = false;
350
+ }
351
+ return ret;
352
+ }
353
+
354
+ ethash_return_value_t ethash_light_compute(
355
+ ethash_light_t light,
356
+ ethash_h256_t const header_hash,
357
+ uint64_t nonce
358
+ )
359
+ {
360
+ uint64_t full_size = ethash_get_datasize(light->block_number);
361
+ return ethash_light_compute_internal(light, full_size, header_hash, nonce);
362
+ }
363
+
364
+ static bool ethash_mmap(struct ethash_full* ret, FILE* f)
365
+ {
366
+ int fd;
367
+ char* mmapped_data;
368
+ errno = 0;
369
+ ret->file = f;
370
+ if ((fd = ethash_fileno(ret->file)) == -1) {
371
+ return false;
372
+ }
373
+ mmapped_data= mmap(
374
+ NULL,
375
+ (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE,
376
+ PROT_READ | PROT_WRITE,
377
+ MAP_SHARED,
378
+ fd,
379
+ 0
380
+ );
381
+ if (mmapped_data == MAP_FAILED) {
382
+ return false;
383
+ }
384
+ ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE);
385
+ return true;
386
+ }
387
+
388
+ ethash_full_t ethash_full_new_internal(
389
+ char const* dirname,
390
+ ethash_h256_t const seed_hash,
391
+ uint64_t full_size,
392
+ ethash_light_t const light,
393
+ ethash_callback_t callback
394
+ )
395
+ {
396
+ struct ethash_full* ret;
397
+ FILE *f = NULL;
398
+ ret = calloc(sizeof(*ret), 1);
399
+ if (!ret) {
400
+ return NULL;
401
+ }
402
+ ret->file_size = (size_t)full_size;
403
+ switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
404
+ case ETHASH_IO_FAIL:
405
+ // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
406
+ goto fail_free_full;
407
+ case ETHASH_IO_MEMO_MATCH:
408
+ if (!ethash_mmap(ret, f)) {
409
+ ETHASH_CRITICAL("mmap failure()");
410
+ goto fail_close_file;
411
+ }
412
+ return ret;
413
+ case ETHASH_IO_MEMO_SIZE_MISMATCH:
414
+ // if a DAG of same filename but unexpected size is found, silently force new file creation
415
+ if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
416
+ ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
417
+ goto fail_free_full;
418
+ }
419
+ // fallthrough to the mismatch case here, DO NOT go through match
420
+ case ETHASH_IO_MEMO_MISMATCH:
421
+ if (!ethash_mmap(ret, f)) {
422
+ ETHASH_CRITICAL("mmap failure()");
423
+ goto fail_close_file;
424
+ }
425
+ break;
426
+ }
427
+
428
+ if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
429
+ ETHASH_CRITICAL("Failure at computing DAG data.");
430
+ goto fail_free_full_data;
431
+ }
432
+
433
+ // after the DAG has been filled then we finalize it by writting the magic number at the beginning
434
+ if (fseek(f, 0, SEEK_SET) != 0) {
435
+ ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
436
+ goto fail_free_full_data;
437
+ }
438
+ uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
439
+ if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
440
+ ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
441
+ goto fail_free_full_data;
442
+ }
443
+ if (fflush(f) != 0) {// make sure the magic number IS there
444
+ ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
445
+ goto fail_free_full_data;
446
+ }
447
+ return ret;
448
+
449
+ fail_free_full_data:
450
+ // could check that munmap(..) == 0 but even if it did not can't really do anything here
451
+ munmap(ret->data, (size_t)full_size);
452
+ fail_close_file:
453
+ fclose(ret->file);
454
+ fail_free_full:
455
+ free(ret);
456
+ return NULL;
457
+ }
458
+
459
+ ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
460
+ {
461
+ char strbuf[256];
462
+ if (!ethash_get_default_dirname(strbuf, 256)) {
463
+ return NULL;
464
+ }
465
+ uint64_t full_size = ethash_get_datasize(light->block_number);
466
+ ethash_h256_t seedhash = ethash_get_seedhash(light->block_number);
467
+ return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback);
468
+ }
469
+
470
+ void ethash_full_delete(ethash_full_t full)
471
+ {
472
+ // could check that munmap(..) == 0 but even if it did not can't really do anything here
473
+ munmap(full->data, (size_t)full->file_size);
474
+ if (full->file) {
475
+ fclose(full->file);
476
+ }
477
+ free(full);
478
+ }
479
+
480
+ ethash_return_value_t ethash_full_compute(
481
+ ethash_full_t full,
482
+ ethash_h256_t const header_hash,
483
+ uint64_t nonce
484
+ )
485
+ {
486
+ ethash_return_value_t ret;
487
+ ret.success = true;
488
+ if (!ethash_hash(
489
+ &ret,
490
+ (node const*)full->data,
491
+ NULL,
492
+ full->file_size,
493
+ header_hash,
494
+ nonce)) {
495
+ ret.success = false;
496
+ }
497
+ return ret;
498
+ }
499
+
500
+ void const* ethash_full_dag(ethash_full_t full)
501
+ {
502
+ return full->data;
503
+ }
504
+
505
+ uint64_t ethash_full_dag_size(ethash_full_t full)
506
+ {
507
+ return full->file_size;
508
+ }