Commit ff5578fc authored by obscuren's avatar obscuren

updated ethash

parent a2e3bf6f
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
}, },
{ {
"ImportPath": "github.com/ethereum/ethash", "ImportPath": "github.com/ethereum/ethash",
"Comment": "v23.1-30-gf8a0565", "Comment": "v23.1-33-g6ecb8e6",
"Rev": "f8a0565cc3a20c5ad82dec3ec612645356069641" "Rev": "6ecb8e610d60240187b44f61e66b06198c26fae6"
}, },
{ {
"ImportPath": "github.com/ethereum/serpent-go", "ImportPath": "github.com/ethereum/serpent-go",
......
...@@ -85,7 +85,7 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*Params ...@@ -85,7 +85,7 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*Params
Epoch: blockNum / epochLength, Epoch: blockNum / epochLength,
} }
C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum))) C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum)))
paramsAndCache.cache.mem = C.malloc(C.size_t(paramsAndCache.params.cache_size)) paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size)
seedHash, err := GetSeedHash(blockNum) seedHash, err := GetSeedHash(blockNum)
if err != nil { if err != nil {
...@@ -118,7 +118,7 @@ func (pow *Ethash) UpdateCache(force bool) error { ...@@ -118,7 +118,7 @@ func (pow *Ethash) UpdateCache(force bool) error {
func makeDAG(p *ParamsAndCache) *DAG { func makeDAG(p *ParamsAndCache) *DAG {
d := &DAG{ d := &DAG{
dag: C.malloc(C.size_t(p.params.full_size)), dag: C.malloc(p.params.full_size),
file: false, file: false,
paramsAndCache: p, paramsAndCache: p,
} }
...@@ -360,10 +360,11 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte ...@@ -360,10 +360,11 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte
} }
func (pow *Ethash) Verify(block pow.Block) bool { func (pow *Ethash) Verify(block pow.Block) bool {
return pow.verify(block.HashNoNonce().Bytes(), block.MixDigest().Bytes(), block.Difficulty(), block.NumberU64(), block.Nonce())
return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce())
} }
func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool { func (pow *Ethash) verify(hash common.Hash, mixDigest common.Hash, difficulty *big.Int, blockNum uint64, nonce uint64) bool {
// Make sure the block num is valid // Make sure the block num is valid
if blockNum >= epochLength*2048 { if blockNum >= epochLength*2048 {
powlogger.Infoln(fmt.Sprintf("Block number exceeds limit, invalid (value is %v, limit is %v)", powlogger.Infoln(fmt.Sprintf("Block number exceeds limit, invalid (value is %v, limit is %v)",
......
...@@ -7,73 +7,84 @@ ...@@ -7,73 +7,84 @@
var Keccak = require('./keccak'); var Keccak = require('./keccak');
var util = require('./util'); var util = require('./util');
var ethUtil = require('ethereumjs-util');
// 32-bit unsigned modulo // 32-bit unsigned modulo
function mod32(x, n) { function mod32(x, n)
return (x >>> 0) % (n >>> 0); {
return (x>>>0) % (n>>>0);
} }
function fnv(x, y) { function fnv(x, y)
{
// js integer multiply by 0x01000193 will lose precision // js integer multiply by 0x01000193 will lose precision
return ((x * 0x01000000 | 0) + (x * 0x193 | 0)) ^ y; return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y;
} }
function computeCache(params, seedWords) { function computeCache(params, seedWords)
{
var cache = new Uint32Array(params.cacheSize >> 2); var cache = new Uint32Array(params.cacheSize >> 2);
var cacheNodeCount = params.cacheSize >> 6; var cacheNodeCount = params.cacheSize >> 6;
// Initialize cache // Initialize cache
var keccak = new Keccak(); var keccak = new Keccak();
keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length); keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length);
for (var n = 1; n < cacheNodeCount; ++n) { for (var n = 1; n < cacheNodeCount; ++n)
keccak.digestWords(cache, n << 4, 16, cache, (n - 1) << 4, 16); {
keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16);
} }
var tmp = new Uint32Array(16); var tmp = new Uint32Array(16);
// Do randmemohash passes // Do randmemohash passes
for (var r = 0; r < params.cacheRounds; ++r) { for (var r = 0; r < params.cacheRounds; ++r)
for (var n = 0; n < cacheNodeCount; ++n) { {
for (var n = 0; n < cacheNodeCount; ++n)
{
var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4; var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4;
var p1 = mod32(cache[n << 4 | 0], cacheNodeCount) << 4; var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4;
for (var w = 0; w < 16; w = (w + 1) | 0) { for (var w = 0; w < 16; w=(w+1)|0)
{
tmp[w] = cache[p0 | w] ^ cache[p1 | w]; tmp[w] = cache[p0 | w] ^ cache[p1 | w];
} }
keccak.digestWords(cache, n << 4, 16, tmp, 0, tmp.length); keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length);
} }
} }
return cache; return cache;
} }
function computeDagNode(o_node, params, cache, keccak, nodeIndex) { function computeDagNode(o_node, params, cache, keccak, nodeIndex)
{
var cacheNodeCount = params.cacheSize >> 6; var cacheNodeCount = params.cacheSize >> 6;
var dagParents = params.dagParents; var dagParents = params.dagParents;
var c = (nodeIndex % cacheNodeCount) << 4; var c = (nodeIndex % cacheNodeCount) << 4;
var mix = o_node; var mix = o_node;
for (var w = 0; w < 16; ++w) { for (var w = 0; w < 16; ++w)
mix[w] = cache[c | w]; {
mix[w] = cache[c|w];
} }
mix[0] ^= nodeIndex; mix[0] ^= nodeIndex;
keccak.digestWords(mix, 0, 16, mix, 0, 16); keccak.digestWords(mix, 0, 16, mix, 0, 16);
for (var p = 0; p < dagParents; ++p) { for (var p = 0; p < dagParents; ++p)
{
// compute cache node (word) index // compute cache node (word) index
c = mod32(fnv(nodeIndex ^ p, mix[p & 15]), cacheNodeCount) << 4; c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4;
for (var w = 0; w < 16; ++w) { for (var w = 0; w < 16; ++w)
mix[w] = fnv(mix[w], cache[c | w]); {
mix[w] = fnv(mix[w], cache[c|w]);
} }
} }
keccak.digestWords(mix, 0, 16, mix, 0, 16); keccak.digestWords(mix, 0, 16, mix, 0, 16);
} }
function computeHashInner(mix, params, cache, keccak, tempNode) { function computeHashInner(mix, params, cache, keccak, tempNode)
var mixParents = params.mixParents | 0; {
var mixParents = params.mixParents|0;
var mixWordCount = params.mixSize >> 2; var mixWordCount = params.mixSize >> 2;
var mixNodeCount = mixWordCount >> 4; var mixNodeCount = mixWordCount >> 4;
var dagPageCount = (params.dagSize / params.mixSize) >> 0; var dagPageCount = (params.dagSize / params.mixSize) >> 0;
...@@ -82,25 +93,30 @@ function computeHashInner(mix, params, cache, keccak, tempNode) { ...@@ -82,25 +93,30 @@ function computeHashInner(mix, params, cache, keccak, tempNode) {
var s0 = mix[0]; var s0 = mix[0];
// initialise mix from initial 64 bytes // initialise mix from initial 64 bytes
for (var w = 16; w < mixWordCount; ++w) { for (var w = 16; w < mixWordCount; ++w)
{
mix[w] = mix[w & 15]; mix[w] = mix[w & 15];
} }
for (var a = 0; a < mixParents; ++a) { for (var a = 0; a < mixParents; ++a)
var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount - 1)]), dagPageCount); {
var d = (p * mixNodeCount) | 0; var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount);
var d = (p * mixNodeCount)|0;
for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) { for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16)
computeDagNode(tempNode, params, cache, keccak, (d + n) | 0); {
computeDagNode(tempNode, params, cache, keccak, (d + n)|0);
for (var v = 0; v < 16; ++v) { for (var v = 0; v < 16; ++v)
mix[w | v] = fnv(mix[w | v], tempNode[v]); {
mix[w|v] = fnv(mix[w|v], tempNode[v]);
} }
} }
} }
} }
function convertSeed(seed) { function convertSeed(seed)
{
// todo, reconcile with spec, byte ordering? // todo, reconcile with spec, byte ordering?
// todo, big-endian conversion // todo, big-endian conversion
var newSeed = util.toWords(seed); var newSeed = util.toWords(seed);
...@@ -109,54 +125,22 @@ function convertSeed(seed) { ...@@ -109,54 +125,22 @@ function convertSeed(seed) {
return newSeed; return newSeed;
} }
var params = exports.params = { exports.defaultParams = function()
REVISION: 23, {
DATASET_BYTES_INIT: 1073741824,
DATASET_BYTES_GROWTH: 8388608,
CACHE_BYTES_INIT: 1073741824,
CACHE_BYTES_GROWTH: 131072,
EPOCH_LENGTH: 30000,
MIX_BYTES: 128,
HASH_BYTES: 64,
DATASET_PARENTS: 256,
CACHE_ROUNDS: 3,
ACCESSES: 64
};
var cache_sizes = require('./cache_sizes');
var dag_sizes = require('./dag_sizes');
exports.calcSeed = function(blockNum) {
var epoch;
var seed = new Uint8Array(32);
if (blockNum > cache_sizes.length * params.EPOCH_LENGTH) {
return new Error('Time to upgrade to POS!!!');
} else {
epoch = Math.floor(blockNum / params.EPOCH_LENGTH);
for (var i = 0; i < epoch; i++) {
seed = ethUtil.sha3(new Buffer(seed));
}
return seed;
}
};
exports.defaultParams = function() {
return { return {
cacheSize: 1048384, cacheSize: 1048384,
cacheRounds: 3, cacheRounds: 3,
dagSize: 1073739904, dagSize: 1073739904,
dagParents: 256, dagParents: 256,
mixSize: 128, mixSize: 128,
mixParents: 64 mixParents: 64,
}; };
}; };
exports.Ethash = function(params, seed) { exports.Ethash = function(params, seed)
{
// precompute cache and related values // precompute cache and related values
// seed = convertSeed(seed); seed = convertSeed(seed);
var cache = computeCache(params, seed); var cache = computeCache(params, seed);
// preallocate buffers/etc // preallocate buffers/etc
...@@ -170,21 +154,24 @@ exports.Ethash = function(params, seed) { ...@@ -170,21 +154,24 @@ exports.Ethash = function(params, seed) {
var retWords = new Uint32Array(8); var retWords = new Uint32Array(8);
var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only
this.hash = function(header, nonce) { this.hash = function(header, nonce)
{
// compute initial hash // compute initial hash
initBytes.set(header, 0); initBytes.set(header, 0);
initBytes.set(nonce, 32); initBytes.set(nonce, 32);
keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length / 4); keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4);
// compute mix // compute mix
for (var i = 0; i !== 16; ++i) { for (var i = 0; i != 16; ++i)
{
mixWords[i] = initWords[i]; mixWords[i] = initWords[i];
} }
computeHashInner(mixWords, params, cache, keccak, tempNode); computeHashInner(mixWords, params, cache, keccak, tempNode);
// compress mix and append to initWords // compress mix and append to initWords
for (var i = 0; i !== mixWords.length; i += 4) { for (var i = 0; i != mixWords.length; i += 4)
initWords[16 + i / 4] = fnv(fnv(fnv(mixWords[i], mixWords[i + 1]), mixWords[i + 2]), mixWords[i + 3]); {
initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]);
} }
// final Keccak hashes // final Keccak hashes
...@@ -192,7 +179,12 @@ exports.Ethash = function(params, seed) { ...@@ -192,7 +179,12 @@ exports.Ethash = function(params, seed) {
return retBytes; return retBytes;
}; };
this.cacheDigest = function() { this.cacheDigest = function()
{
return keccak.digest(32, new Uint8Array(cache.buffer)); return keccak.digest(32, new Uint8Array(cache.buffer));
}; };
}; };
{
"name": "ethash.js",
"version": "0.0.1",
"description": "",
"main": "ethash.js",
"scripts": {
"test": "node ./test/test.js"
},
"repository": {
"type": "git",
"url": "https://github.com/ethereum/ethash/tree/master/js"
},
"keywords": [
"ethereum"
],
"author": "",
"license": "mit",
"devDependencies": {
"ethereum-tests": "0.0.5"
}
}
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
/*jslint node: true, shadow:true */ /*jslint node: true, shadow:true */
"use strict"; "use strict";
var ethash = require('../ethash'); var ethash = require('./ethash');
var util = require('../util'); var util = require('./util');
var Keccak = require('../keccak'); var Keccak = require('./keccak');
// sanity check hash functions // sanity check hash functions
var src = util.stringToBytes(""); var src = util.stringToBytes("");
...@@ -31,7 +31,7 @@ var ethashParams = ethash.defaultParams(); ...@@ -31,7 +31,7 @@ var ethashParams = ethash.defaultParams();
var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466") var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466")
var startTime = new Date().getTime(); var startTime = new Date().getTime();
var hasher = new ethash.Ethash(ethashParams, seed); var hasher = new ethash.Ethash(ethashParams, seed);
console.log('Ethash startup took: ' + (new Date().getTime() - startTime) + "ms"); console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms");
console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest())); console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest()));
var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
...@@ -45,8 +45,9 @@ var hash; ...@@ -45,8 +45,9 @@ var hash;
startTime = new Date().getTime(); startTime = new Date().getTime();
var trials = 10; var trials = 10;
for (var i = 0; i < trials; ++i) { for (var i = 0; i < trials; ++i)
{
hash = hasher.hash(header, nonce); hash = hasher.hash(header, nonce);
} }
console.log("Light client hashes averaged: " + (new Date().getTime() - startTime) / trials + "ms"); console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms");
console.log("Hash = " + util.bytesToHexString(hash)); console.log("Hash = " + util.bytesToHexString(hash));
var tape = require('tape');
const ethash = require('../ethash.js');
tape('seed hash', function(t) {
t.test('seed should match TRUTH', function(st) {
const seed = '290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563';
const blockNum = 30000;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('seed should match TRUTH2', function(st) {
const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9';
const blockNum = 60000;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('seed should match TRUTH3', function(st) {
const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9';
const blockNum = 60700;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('randomized tests', function(st) {
for (var i = 0; i < 100; i++) {
var x = Math.floor(ethash.params.EPOCH_LENGTH * 2048 * Math.random());
st.equal(ethash.calcSeed(x).toString('hex'), ethash.calcSeed(Math.floor(x / ethash.params.EPOCH_LENGTH) * ethash.params.EPOCH_LENGTH ).toString('hex'));
}
st.end();
});
// '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9'
// [7:13:32 PM] Matthew Wampler-Doty: >>> x = randint(0,700000)
//
// >>> pyethash.get_seedhash(x).encode('hex') == pyethash.get_seedhash((x // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH).encode('hex')
});
...@@ -25,9 +25,9 @@ setup ( ...@@ -25,9 +25,9 @@ setup (
author = "Matthew Wampler-Doty", author = "Matthew Wampler-Doty",
author_email = "matthew.wampler.doty@gmail.com", author_email = "matthew.wampler.doty@gmail.com",
license = 'GPL', license = 'GPL',
version = '23.1', version = '23',
url = 'https://github.com/ethereum/ethash', url = 'https://github.com/ethereum/ethash',
download_url = 'https://github.com/ethereum/ethash/tarball/v23.1', download_url = 'https://github.com/ethereum/ethash/tarball/v23',
description = 'Python wrappers for ethash, the ethereum proof of work hashing function', description = 'Python wrappers for ethash, the ethereum proof of work hashing function',
ext_modules = [pyethash], ext_modules = [pyethash],
) )
...@@ -48,7 +48,7 @@ extern "C" { ...@@ -48,7 +48,7 @@ extern "C" {
// Sow[i*HashBytes]; j++]]]][[2]][[1]] // Sow[i*HashBytes]; j++]]]][[2]][[1]]
static const uint64_t dag_sizes[2048] = { static const size_t dag_sizes[2048] = {
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
...@@ -477,7 +477,7 @@ static const uint64_t dag_sizes[2048] = { ...@@ -477,7 +477,7 @@ static const uint64_t dag_sizes[2048] = {
// While[! PrimeQ[i], i--]; // While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]] // Sow[i*HashBytes]; j++]]]][[2]][[1]]
const uint64_t cache_sizes[2048] = { const size_t cache_sizes[2048] = {
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
......
...@@ -43,8 +43,8 @@ extern "C" { ...@@ -43,8 +43,8 @@ extern "C" {
#endif #endif
typedef struct ethash_params { typedef struct ethash_params {
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params; } ethash_params;
typedef struct ethash_return_value { typedef struct ethash_return_value {
...@@ -52,52 +52,45 @@ typedef struct ethash_return_value { ...@@ -52,52 +52,45 @@ typedef struct ethash_return_value {
uint8_t mix_hash[32]; uint8_t mix_hash[32];
} ethash_return_value; } ethash_return_value;
uint64_t ethash_get_datasize(const uint32_t block_number); size_t ethash_get_datasize(const uint32_t block_number);
uint64_t ethash_get_cachesize(const uint32_t block_number); size_t ethash_get_cachesize(const uint32_t block_number);
// Initialize the Parameters // initialize the parameters
static inline int ethash_params_init(ethash_params *params, const uint32_t block_number) { static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number); params->full_size = ethash_get_datasize(block_number);
if (params->full_size == 0)
return 0;
params->cache_size = ethash_get_cachesize(block_number); params->cache_size = ethash_get_cachesize(block_number);
if (params->cache_size == 0)
return 0;
return 1;
} }
typedef struct ethash_cache { typedef struct ethash_cache {
void *mem; void *mem;
} ethash_cache; } ethash_cache;
int ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
int ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
static inline int ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) {
ethash_cache c; ethash_cache c;
c.mem = cache; c.mem = cache;
return ethash_mkcache(&c, params, seed); ethash_mkcache(&c, params, seed);
} }
static inline int ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_cache c; ethash_cache c;
c.mem = (void *) cache; c.mem = (void *) cache;
return ethash_light(ret, &c, params, header_hash, nonce); ethash_light(ret, &c, params, header_hash, nonce);
} }
static inline int ethash_prep_full(void *full, ethash_params const *params, void const *cache) { static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_cache c; ethash_cache c;
c.mem = (void *) cache; c.mem = (void *) cache;
return ethash_compute_full_data(full, params, &c); ethash_compute_full_data(full, params, &c);
} }
static inline int ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
return ethash_full(ret, full, params, header_hash, nonce); ethash_full(ret, full, params, header_hash, nonce);
} }
// Returns if hash is less than or equal to difficulty // Returns if hash is less than or equal to difficulty
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
* @date 2015 * @date 2015
*/ */
#include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <stddef.h> #include <stddef.h>
#include "ethash.h" #include "ethash.h"
...@@ -28,9 +29,6 @@ ...@@ -28,9 +29,6 @@
#include "internal.h" #include "internal.h"
#include "data_sizes.h" #include "data_sizes.h"
// Inline assembly doesn't work
#define ENABLE_SSE 0
#ifdef WITH_CRYPTOPP #ifdef WITH_CRYPTOPP
#include "sha3_cryptopp.h" #include "sha3_cryptopp.h"
...@@ -39,29 +37,24 @@ ...@@ -39,29 +37,24 @@
#include "sha3.h" #include "sha3.h"
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) { size_t ethash_get_datasize(const uint32_t block_number) {
if (block_number / EPOCH_LENGTH >= 2048) assert(block_number / EPOCH_LENGTH < 2048);
return 0;
return dag_sizes[block_number / EPOCH_LENGTH]; return dag_sizes[block_number / EPOCH_LENGTH];
} }
uint64_t ethash_get_cachesize(const uint32_t block_number) { size_t ethash_get_cachesize(const uint32_t block_number) {
if (block_number / EPOCH_LENGTH >= 2048) assert(block_number / EPOCH_LENGTH < 2048);
return 0;
return cache_sizes[block_number / EPOCH_LENGTH]; return cache_sizes[block_number / EPOCH_LENGTH];
} }
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N) // SeqMemoHash(s, R, N)
int static ethash_compute_cache_nodes( void static ethash_compute_cache_nodes(
node *const nodes, node *const nodes,
ethash_params const *params, ethash_params const *params,
const uint8_t seed[32]) { const uint8_t seed[32]) {
assert((params->cache_size % sizeof(node)) == 0);
if ((params->cache_size % sizeof(node)) != 0)
return 0;
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, seed, 32); SHA3_512(nodes[0].bytes, seed, 32);
...@@ -89,27 +82,22 @@ int static ethash_compute_cache_nodes( ...@@ -89,27 +82,22 @@ int static ethash_compute_cache_nodes(
nodes->words[w] = fix_endian32(nodes->words[w]); nodes->words[w] = fix_endian32(nodes->words[w]);
} }
#endif #endif
return 1;
} }
int ethash_mkcache( void ethash_mkcache(
ethash_cache *cache, ethash_cache *cache,
ethash_params const *params, ethash_params const *params,
const uint8_t seed[32]) { const uint8_t seed[32]) {
node *nodes = (node *) cache->mem; node *nodes = (node *) cache->mem;
return ethash_compute_cache_nodes(nodes, params, seed); ethash_compute_cache_nodes(nodes, params, seed);
} }
int ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node *const ret,
const uint64_t node_index, const unsigned node_index,
const struct ethash_params *params, const struct ethash_params *params,
const struct ethash_cache *cache) { const struct ethash_cache *cache) {
if (params->cache_size % sizeof(node) != 0)
return 0;
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem; node const *cache_nodes = (node const *) cache->mem;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const *init = &cache_nodes[node_index % num_parent_nodes];
...@@ -157,58 +145,23 @@ int ethash_calculate_dag_item( ...@@ -157,58 +145,23 @@ int ethash_calculate_dag_item(
} }
SHA3_512(ret->bytes, ret->bytes, sizeof(node)); SHA3_512(ret->bytes, ret->bytes, sizeof(node));
return 1;
} }
int ethash_compute_full_data( void ethash_compute_full_data(
void *mem, void *mem,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache) { ethash_cache const *cache) {
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0);
if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0) assert((params->full_size % sizeof(node)) == 0);
return 0;
if ((params->full_size % sizeof(node)) != 0)
return 0;
node *full_nodes = mem;
// now compute full nodes
for (uint64_t n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
}
return 1;
}
int ethash_compute_full_data_section(
void *mem,
ethash_params const *params,
ethash_cache const *cache,
uint64_t const start,
uint64_t const end) {
if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0)
return 0;
if ((params->full_size % sizeof(node)) != 0)
return 0;
if (end >= params->full_size)
return 0;
if (start >= end)
return 0;
node *full_nodes = mem; node *full_nodes = mem;
// now compute full nodes // now compute full nodes
for (uint64_t n = start; n != end; ++n) { for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
} }
return 1;
} }
static int ethash_hash( static void ethash_hash(
ethash_return_value *ret, ethash_return_value *ret,
node const *full_nodes, node const *full_nodes,
ethash_cache const *cache, ethash_cache const *cache,
...@@ -216,10 +169,10 @@ static int ethash_hash( ...@@ -216,10 +169,10 @@ static int ethash_hash(
const uint8_t header_hash[32], const uint8_t header_hash[32],
const uint64_t nonce) { const uint64_t nonce) {
if ((params->full_size % MIX_WORDS) != 0) assert((params->full_size % MIX_WORDS) == 0);
return 0;
// pack hash and nonce together into first 40 bytes of s_mix // pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1]; node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32); memcpy(s_mix[0].bytes, header_hash, 32);
...@@ -301,7 +254,6 @@ static int ethash_hash( ...@@ -301,7 +254,6 @@ static int ethash_hash(
memcpy(ret->mix_hash, mix->bytes, 32); memcpy(ret->mix_hash, mix->bytes, 32);
// final Keccak hash // final Keccak hash
SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return 1;
} }
void ethash_quick_hash( void ethash_quick_hash(
...@@ -339,10 +291,10 @@ int ethash_quick_check_difficulty( ...@@ -339,10 +291,10 @@ int ethash_quick_check_difficulty(
return ethash_check_difficulty(return_hash, difficulty); return ethash_check_difficulty(return_hash, difficulty);
} }
int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
return ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
} }
int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
return ethash_hash(ret, NULL, cache, params, previous_hash, nonce); ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
} }
\ No newline at end of file
...@@ -30,9 +30,9 @@ typedef union node { ...@@ -30,9 +30,9 @@ typedef union node {
} node; } node;
int ethash_calculate_dag_item( void ethash_calculate_dag_item(
node *const ret, node *const ret,
const uint64_t node_index, const unsigned node_index,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache ethash_cache const *cache
); );
......
...@@ -58,7 +58,7 @@ mkcache_bytes(PyObject *self, PyObject *args) { ...@@ -58,7 +58,7 @@ mkcache_bytes(PyObject *self, PyObject *args) {
} }
ethash_params params; ethash_params params;
params.cache_size = (uint64_t) cache_size; params.cache_size = (size_t) cache_size;
ethash_cache cache; ethash_cache cache;
cache.mem = malloc(cache_size); cache.mem = malloc(cache_size);
ethash_mkcache(&cache, &params, (uint8_t *) seed); ethash_mkcache(&cache, &params, (uint8_t *) seed);
...@@ -92,8 +92,8 @@ calc_dataset_bytes(PyObject *self, PyObject *args) { ...@@ -92,8 +92,8 @@ calc_dataset_bytes(PyObject *self, PyObject *args) {
} }
ethash_params params; ethash_params params;
params.cache_size = (uint64_t) cache_size; params.cache_size = (size_t) cache_size;
params.full_size = (uint64_t) full_size; params.full_size = (size_t) full_size;
ethash_cache cache; ethash_cache cache;
cache.mem = (void *) cache_bytes; cache.mem = (void *) cache_bytes;
void *mem = malloc(params.full_size); void *mem = malloc(params.full_size);
...@@ -138,8 +138,8 @@ hashimoto_light(PyObject *self, PyObject *args) { ...@@ -138,8 +138,8 @@ hashimoto_light(PyObject *self, PyObject *args) {
ethash_return_value out; ethash_return_value out;
ethash_params params; ethash_params params;
params.cache_size = (uint64_t) cache_size; params.cache_size = (size_t) cache_size;
params.full_size = (uint64_t) full_size; params.full_size = (size_t) full_size;
ethash_cache cache; ethash_cache cache;
cache.mem = (void *) cache_bytes; cache.mem = (void *) cache_bytes;
ethash_light(&out, &cache, &params, (uint8_t *) header, nonce); ethash_light(&out, &cache, &params, (uint8_t *) header, nonce);
...@@ -175,7 +175,7 @@ hashimoto_full(PyObject *self, PyObject *args) { ...@@ -175,7 +175,7 @@ hashimoto_full(PyObject *self, PyObject *args) {
ethash_return_value out; ethash_return_value out;
ethash_params params; ethash_params params;
params.full_size = (uint64_t) full_size; params.full_size = (size_t) full_size;
ethash_full(&out, (void *) full_bytes, &params, (uint8_t *) header, nonce); ethash_full(&out, (void *) full_bytes, &params, (uint8_t *) header, nonce);
return Py_BuildValue("{s:s#, s:s#}", return Py_BuildValue("{s:s#, s:s#}",
"mix digest", out.mix_hash, 32, "mix digest", out.mix_hash, 32,
...@@ -216,7 +216,7 @@ mine(PyObject *self, PyObject *args) { ...@@ -216,7 +216,7 @@ mine(PyObject *self, PyObject *args) {
ethash_return_value out; ethash_return_value out;
ethash_params params; ethash_params params;
params.full_size = (uint64_t) full_size; params.full_size = (size_t) full_size;
// TODO: Multi threading? // TODO: Multi threading?
do { do {
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <iostream> #include <iostream>
std::string bytesToHexString(const uint8_t *str, const uint32_t s) { std::string bytesToHexString(const uint8_t *str, const size_t s) {
std::ostringstream ret; std::ostringstream ret;
for (int i = 0; i < s; ++i) for (int i = 0; i < s; ++i)
...@@ -80,11 +80,9 @@ BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) { ...@@ -80,11 +80,9 @@ BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) {
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) { BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) {
ethash_params params; ethash_params params;
BOOST_REQUIRE_MESSAGE(ethash_params_init(&params, 0), ethash_params_init(&params, 0);
"Params could not be initialized"); const uint32_t expected_full_size = 1073739904;
const uint32_t const uint32_t expected_cache_size = 16776896;
expected_full_size = 1073739904,
expected_cache_size = 16776896;
BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size, BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size,
"\nexpected: " << expected_cache_size << "\n" "\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.full_size << "\n"); << "actual: " << params.full_size << "\n");
......
...@@ -14,8 +14,11 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" ...@@ -14,8 +14,11 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo -e "\n################# Testing JS ##################" echo -e "\n################# Testing JS ##################"
# TODO: Use mocha and real testing tools instead of rolling our own # TODO: Use mocha and real testing tools instead of rolling our own
cd $TEST_DIR/../js cd $TEST_DIR/../js
if [ -x "$(which npm)" ] ; then if [ -x "$(which nodejs)" ] ; then
npm test nodejs test.js
fi
if [ -x "$(which node)" ] ; then
node test.js
fi fi
echo -e "\n################# Testing C ##################" echo -e "\n################# Testing C ##################"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment