Jorge Zaccaro
9 years ago
commit
3606036e3a
2 changed files with 124 additions and 0 deletions
@ -0,0 +1,101 @@ |
|||
'use strict'; |
|||
|
|||
module.exports = generate; |
|||
|
|||
var crypto = require('crypto'), |
|||
async = require('async'); |
|||
|
|||
/*--------------------------------------------------------------------------------*/ |
|||
|
|||
/** Generates a merkle root from an array of hash leaves |
|||
* @param {object} array - The array of hash leaves |
|||
* @param {object} [options] |
|||
* @param {boolean} [options.reverse=true] - Indicates the leaves and root hashes should be reversed (endianness) |
|||
* @param {function} callback(err, merkleObject) |
|||
*/ |
|||
function generate(array, options, callback) { |
|||
if (typeof options === 'function') { |
|||
callback = options; |
|||
options = {}; |
|||
} |
|||
|
|||
/* Check if the hashes should be reversed for proper endianness */ |
|||
if (options.reverse === false) { |
|||
recursiveMerkle(array, callback); |
|||
} else { |
|||
reverseHashes(array, function (err, reversedHashes) { |
|||
if (err) { |
|||
return callback(err); |
|||
} |
|||
|
|||
recursiveMerkle(reversedHashes, function (err, merkle) { |
|||
if (err) { |
|||
return callback(err); |
|||
} |
|||
|
|||
merkle.root = merkle.root.match(/.{2}/g).reverse().join(''); |
|||
callback(null, merkle); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/** Recursively computes the nodes and root of a merkle tree |
|||
* @param {object} hashes - An array of hash leaves |
|||
* @param {function} callback - Invoked when the tree is computed |
|||
*/ |
|||
function recursiveMerkle(hashes, callback) { |
|||
var concatHashes = [], merkleTree = {}; |
|||
|
|||
/* Duplicate last element if the array length is odd */ |
|||
if (hashes.length % 2 === 1) { |
|||
hashes.push(hashes[hashes.length - 1]); |
|||
} |
|||
|
|||
/* Concatenate hashes and push them to a new array */ |
|||
for (var i = 0, length = hashes.length; i < length; i += 2) { |
|||
concatHashes.push(hashes[i] + hashes[i + 1]); |
|||
} |
|||
|
|||
/* Map every element of the new array with a hash function */ |
|||
async.map(concatHashes, function (data, callback) { |
|||
var hash = doubleHash(data); |
|||
callback(null, hash); |
|||
}, function (err, newHashes) { |
|||
if (err) { |
|||
return callback(err); |
|||
} |
|||
|
|||
/* Check if the root has not been reached yet */ |
|||
if (newHashes.length > 1) { |
|||
recursiveMerkle(newHashes, callback); |
|||
} else { |
|||
merkleTree.root = newHashes[0] || ' '; |
|||
callback(null, merkleTree); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/*--------------------------------------------------------------------------------*/ |
|||
|
|||
/** Reverses the bytes of each element of an array of hashes |
|||
* @param {object} hashes - The array of hashes whose elements must be reversed |
|||
* @param {function} whenReversed(err, reversedHashes) - A function to invoke when the operation is completed |
|||
*/ |
|||
function reverseHashes(hashes, whenReversed) { |
|||
var reversedHashes = async.map(hashes, function (element, callback) { |
|||
callback(null, element.match(/.{2}/g).reverse().join('')); |
|||
}, whenReversed); |
|||
} |
|||
|
|||
/** Hashes the input data twice |
|||
* @param {string} data - The data to be double hashed |
|||
* @param {string} [algorithm=sha256] - The hashing algorithm to be used |
|||
* @returns {string} hash2 - The double hash of the input data |
|||
*/ |
|||
function doubleHash(data, algorithm) { |
|||
algorithm = algorithm || 'sha256'; |
|||
var hash1 = crypto.createHash(algorithm).update(new Buffer(data, 'hex')).digest(); |
|||
var hash2 = crypto.createHash(algorithm).update(hash1).digest('hex'); |
|||
return hash2; |
|||
} |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"main": "merkle.js", |
|||
"name": "merkle-bitcoin", |
|||
"version": "1.0.0", |
|||
"description": "Bitcoin-style merkle root generation.", |
|||
"homepage": "https://github.com/jorgezaccaro/merkle-bitcoin", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git://github.com/jorgezaccaro/merkle-bitcoin.git" |
|||
}, |
|||
"keywords": [ |
|||
"merkle", |
|||
"bitcoin" |
|||
], |
|||
"author": { |
|||
"name": "Jorge Zaccaro", |
|||
"email": "jorgezaccaro@gmail.com" |
|||
}, |
|||
"dependencies": { |
|||
"async": "^1.2.1" |
|||
}, |
|||
"license": "MIT" |
|||
} |
Loading…
Reference in new issue