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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.gitmodules +3 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/Rakefile +15 -0
- data/ethash.gemspec +23 -0
- data/ext/ethash/ethash.c +75 -0
- data/ext/ethash/extconf.rb +7 -0
- data/ext/ethash/headers/compiler.h +33 -0
- data/ext/ethash/headers/data_sizes.h +812 -0
- data/ext/ethash/headers/endian.h +79 -0
- data/ext/ethash/headers/ethash.h +147 -0
- data/ext/ethash/headers/fnv.h +43 -0
- data/ext/ethash/headers/internal.h +179 -0
- data/ext/ethash/headers/io.h +202 -0
- data/ext/ethash/headers/mmap.h +47 -0
- data/ext/ethash/headers/sha3.h +31 -0
- data/ext/ethash/headers/sha3_cryptopp.h +18 -0
- data/ext/ethash/headers/util.h +47 -0
- data/ext/ethash/internal.c +508 -0
- data/ext/ethash/io.c +119 -0
- data/ext/ethash/sha3.c +151 -0
- data/lib/ethash.rb +3 -0
- data/lib/ethash/version.rb +5 -0
- data/test/ethash_test.rb +26 -0
- metadata +130 -0
data/ext/ethash/io.c
ADDED
@@ -0,0 +1,119 @@
|
|
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.c
|
18
|
+
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
19
|
+
* @date 2015
|
20
|
+
*/
|
21
|
+
#include "headers/io.h"
|
22
|
+
#include <string.h>
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <errno.h>
|
25
|
+
|
26
|
+
enum ethash_io_rc ethash_io_prepare(
|
27
|
+
char const* dirname,
|
28
|
+
ethash_h256_t const seedhash,
|
29
|
+
FILE** output_file,
|
30
|
+
uint64_t file_size,
|
31
|
+
bool force_create
|
32
|
+
)
|
33
|
+
{
|
34
|
+
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
|
35
|
+
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
36
|
+
// reset errno before io calls
|
37
|
+
errno = 0;
|
38
|
+
|
39
|
+
// assert directory exists
|
40
|
+
if (!ethash_mkdir(dirname)) {
|
41
|
+
ETHASH_CRITICAL("Could not create the ethash directory");
|
42
|
+
goto end;
|
43
|
+
}
|
44
|
+
|
45
|
+
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
|
46
|
+
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
|
47
|
+
if (!tmpfile) {
|
48
|
+
ETHASH_CRITICAL("Could not create the full DAG pathname");
|
49
|
+
goto end;
|
50
|
+
}
|
51
|
+
|
52
|
+
FILE *f;
|
53
|
+
if (!force_create) {
|
54
|
+
// try to open the file
|
55
|
+
f = ethash_fopen(tmpfile, "rb+");
|
56
|
+
if (f) {
|
57
|
+
size_t found_size;
|
58
|
+
if (!ethash_file_size(f, &found_size)) {
|
59
|
+
fclose(f);
|
60
|
+
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
|
61
|
+
goto free_memo;
|
62
|
+
}
|
63
|
+
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
|
64
|
+
fclose(f);
|
65
|
+
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
66
|
+
goto free_memo;
|
67
|
+
}
|
68
|
+
// compare the magic number, no need to care about endianess since it's local
|
69
|
+
uint64_t magic_num;
|
70
|
+
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
71
|
+
// I/O error
|
72
|
+
fclose(f);
|
73
|
+
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
|
74
|
+
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
75
|
+
goto free_memo;
|
76
|
+
}
|
77
|
+
if (magic_num != ETHASH_DAG_MAGIC_NUM) {
|
78
|
+
fclose(f);
|
79
|
+
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
80
|
+
goto free_memo;
|
81
|
+
}
|
82
|
+
ret = ETHASH_IO_MEMO_MATCH;
|
83
|
+
goto set_file;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
// file does not exist, will need to be created
|
88
|
+
f = ethash_fopen(tmpfile, "wb+");
|
89
|
+
if (!f) {
|
90
|
+
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
|
91
|
+
goto free_memo;
|
92
|
+
}
|
93
|
+
// make sure it's of the proper size
|
94
|
+
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
|
95
|
+
fclose(f);
|
96
|
+
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
97
|
+
goto free_memo;
|
98
|
+
}
|
99
|
+
if (fputc('\n', f) == EOF) {
|
100
|
+
fclose(f);
|
101
|
+
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
102
|
+
goto free_memo;
|
103
|
+
}
|
104
|
+
if (fflush(f) != 0) {
|
105
|
+
fclose(f);
|
106
|
+
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
107
|
+
goto free_memo;
|
108
|
+
}
|
109
|
+
ret = ETHASH_IO_MEMO_MISMATCH;
|
110
|
+
goto set_file;
|
111
|
+
|
112
|
+
ret = ETHASH_IO_MEMO_MATCH;
|
113
|
+
set_file:
|
114
|
+
*output_file = f;
|
115
|
+
free_memo:
|
116
|
+
free(tmpfile);
|
117
|
+
end:
|
118
|
+
return ret;
|
119
|
+
}
|
data/ext/ethash/sha3.c
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
/** libkeccak-tiny
|
2
|
+
*
|
3
|
+
* A single-file implementation of SHA-3 and SHAKE.
|
4
|
+
*
|
5
|
+
* Implementor: David Leon Gil
|
6
|
+
* License: CC0, attribution kindly requested. Blame taken too,
|
7
|
+
* but not liability.
|
8
|
+
*/
|
9
|
+
#include "headers/sha3.h"
|
10
|
+
|
11
|
+
#include <stdint.h>
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <stdlib.h>
|
14
|
+
#include <string.h>
|
15
|
+
|
16
|
+
/******** The Keccak-f[1600] permutation ********/
|
17
|
+
|
18
|
+
/*** Constants. ***/
|
19
|
+
static const uint8_t rho[24] = \
|
20
|
+
{ 1, 3, 6, 10, 15, 21,
|
21
|
+
28, 36, 45, 55, 2, 14,
|
22
|
+
27, 41, 56, 8, 25, 43,
|
23
|
+
62, 18, 39, 61, 20, 44};
|
24
|
+
static const uint8_t pi[24] = \
|
25
|
+
{10, 7, 11, 17, 18, 3,
|
26
|
+
5, 16, 8, 21, 24, 4,
|
27
|
+
15, 23, 19, 13, 12, 2,
|
28
|
+
20, 14, 22, 9, 6, 1};
|
29
|
+
static const uint64_t RC[24] = \
|
30
|
+
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
|
31
|
+
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
|
32
|
+
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
|
33
|
+
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
|
34
|
+
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
|
35
|
+
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
|
36
|
+
|
37
|
+
/*** Helper macros to unroll the permutation. ***/
|
38
|
+
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
|
39
|
+
#define REPEAT6(e) e e e e e e
|
40
|
+
#define REPEAT24(e) REPEAT6(e e e e)
|
41
|
+
#define REPEAT5(e) e e e e e
|
42
|
+
#define FOR5(v, s, e) \
|
43
|
+
v = 0; \
|
44
|
+
REPEAT5(e; v += s;)
|
45
|
+
|
46
|
+
/*** Keccak-f[1600] ***/
|
47
|
+
static inline void keccakf(void* state) {
|
48
|
+
uint64_t* a = (uint64_t*)state;
|
49
|
+
uint64_t b[5] = {0};
|
50
|
+
uint64_t t = 0;
|
51
|
+
uint8_t x, y;
|
52
|
+
|
53
|
+
for (int i = 0; i < 24; i++) {
|
54
|
+
// Theta
|
55
|
+
FOR5(x, 1,
|
56
|
+
b[x] = 0;
|
57
|
+
FOR5(y, 5,
|
58
|
+
b[x] ^= a[x + y]; ))
|
59
|
+
FOR5(x, 1,
|
60
|
+
FOR5(y, 5,
|
61
|
+
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
62
|
+
// Rho and pi
|
63
|
+
t = a[1];
|
64
|
+
x = 0;
|
65
|
+
REPEAT24(b[0] = a[pi[x]];
|
66
|
+
a[pi[x]] = rol(t, rho[x]);
|
67
|
+
t = b[0];
|
68
|
+
x++; )
|
69
|
+
// Chi
|
70
|
+
FOR5(y,
|
71
|
+
5,
|
72
|
+
FOR5(x, 1,
|
73
|
+
b[x] = a[y + x];)
|
74
|
+
FOR5(x, 1,
|
75
|
+
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
76
|
+
// Iota
|
77
|
+
a[0] ^= RC[i];
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
/******** The FIPS202-defined functions. ********/
|
82
|
+
|
83
|
+
/*** Some helper macros. ***/
|
84
|
+
|
85
|
+
#define _(S) do { S } while (0)
|
86
|
+
#define FOR(i, ST, L, S) \
|
87
|
+
_(for (size_t i = 0; i < L; i += ST) { S; })
|
88
|
+
#define mkapply_ds(NAME, S) \
|
89
|
+
static inline void NAME(uint8_t* dst, \
|
90
|
+
const uint8_t* src, \
|
91
|
+
size_t len) { \
|
92
|
+
FOR(i, 1, len, S); \
|
93
|
+
}
|
94
|
+
#define mkapply_sd(NAME, S) \
|
95
|
+
static inline void NAME(const uint8_t* src, \
|
96
|
+
uint8_t* dst, \
|
97
|
+
size_t len) { \
|
98
|
+
FOR(i, 1, len, S); \
|
99
|
+
}
|
100
|
+
|
101
|
+
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
|
102
|
+
mkapply_sd(setout, dst[i] = src[i]) // setout
|
103
|
+
|
104
|
+
#define P keccakf
|
105
|
+
#define Plen 200
|
106
|
+
|
107
|
+
// Fold P*F over the full blocks of an input.
|
108
|
+
#define foldP(I, L, F) \
|
109
|
+
while (L >= rate) { \
|
110
|
+
F(a, I, rate); \
|
111
|
+
P(a); \
|
112
|
+
I += rate; \
|
113
|
+
L -= rate; \
|
114
|
+
}
|
115
|
+
|
116
|
+
/** The sponge-based hash construction. **/
|
117
|
+
static inline int hash(uint8_t* out, size_t outlen,
|
118
|
+
const uint8_t* in, size_t inlen,
|
119
|
+
size_t rate, uint8_t delim) {
|
120
|
+
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
|
121
|
+
return -1;
|
122
|
+
}
|
123
|
+
uint8_t a[Plen] = {0};
|
124
|
+
// Absorb input.
|
125
|
+
foldP(in, inlen, xorin);
|
126
|
+
// Xor in the DS and pad frame.
|
127
|
+
a[inlen] ^= delim;
|
128
|
+
a[rate - 1] ^= 0x80;
|
129
|
+
// Xor in the last block.
|
130
|
+
xorin(a, in, inlen);
|
131
|
+
// Apply P
|
132
|
+
P(a);
|
133
|
+
// Squeeze output.
|
134
|
+
foldP(out, outlen, setout);
|
135
|
+
setout(a, out, outlen);
|
136
|
+
memset(a, 0, 200);
|
137
|
+
return 0;
|
138
|
+
}
|
139
|
+
|
140
|
+
#define defsha3(bits) \
|
141
|
+
int sha3_##bits(uint8_t* out, size_t outlen, \
|
142
|
+
const uint8_t* in, size_t inlen) { \
|
143
|
+
if (outlen > (bits/8)) { \
|
144
|
+
return -1; \
|
145
|
+
} \
|
146
|
+
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
|
147
|
+
}
|
148
|
+
|
149
|
+
/*** FIPS202 SHA3 FOFs ***/
|
150
|
+
defsha3(256)
|
151
|
+
defsha3(512)
|
data/lib/ethash.rb
ADDED
data/test/ethash_test.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'ethash'
|
7
|
+
|
8
|
+
class EthashTest < Minitest::Test
|
9
|
+
|
10
|
+
def test_mkcache_bytes
|
11
|
+
assert_equal 16776896, Ethash.mkcache_bytes(0).size
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_hashimoto_light
|
15
|
+
cache = Ethash.mkcache_bytes(0)
|
16
|
+
header = "\x01"*32
|
17
|
+
hash = {mixhash: "\xD5\x7F\xB3|OaU\x06\x12\xC0;\x9D\xFB\xC5\xD5;k\x11\xB9\x84\xEFU\xAC\xD7\xDDh\xEC\xF5VF\xA1\xF3", result: "E~\xE8\xA0i\xD4\x18\x95iU\xF9\xA5k*\x02\x1E\xAE~\xBD\x8EoM\x10#\xB67\xFA\xAD)4\x1E\xDD"}
|
18
|
+
assert_equal hash, Ethash.hashimoto_light(0, cache, header, 0)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_get_seedhash
|
22
|
+
assert_equal ")\r\xEC\xD9T\x8Bb\xA8\xD6\x03E\xA9\x888o\xC8K\xA6\xBC\x95H@\b\xF66/\x93\x16\x0E\xF3\xE5c", Ethash.get_seedhash(54321)
|
23
|
+
assert_raises(RuntimeError) { Ethash.get_seedhash(99999999) }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ethash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Xie
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake-compiler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 5.8.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 5.8.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7.6
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.7.6
|
69
|
+
description: Ethash is Ethereum's mining algorithm.
|
70
|
+
email:
|
71
|
+
- jan.h.xie@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions:
|
74
|
+
- ext/ethash/extconf.rb
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".gitmodules"
|
79
|
+
- Gemfile
|
80
|
+
- Gemfile.lock
|
81
|
+
- LICENSE
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- ethash.gemspec
|
85
|
+
- ext/ethash/ethash.c
|
86
|
+
- ext/ethash/extconf.rb
|
87
|
+
- ext/ethash/headers/compiler.h
|
88
|
+
- ext/ethash/headers/data_sizes.h
|
89
|
+
- ext/ethash/headers/endian.h
|
90
|
+
- ext/ethash/headers/ethash.h
|
91
|
+
- ext/ethash/headers/fnv.h
|
92
|
+
- ext/ethash/headers/internal.h
|
93
|
+
- ext/ethash/headers/io.h
|
94
|
+
- ext/ethash/headers/mmap.h
|
95
|
+
- ext/ethash/headers/sha3.h
|
96
|
+
- ext/ethash/headers/sha3_cryptopp.h
|
97
|
+
- ext/ethash/headers/util.h
|
98
|
+
- ext/ethash/internal.c
|
99
|
+
- ext/ethash/io.c
|
100
|
+
- ext/ethash/sha3.c
|
101
|
+
- lib/ethash.rb
|
102
|
+
- lib/ethash/version.rb
|
103
|
+
- test/ethash_test.rb
|
104
|
+
homepage: https://github.com/janx/ruby-ethash
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.4.5.1
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: Ruby binding to libethash.
|
128
|
+
test_files:
|
129
|
+
- test/ethash_test.rb
|
130
|
+
has_rdoc:
|