diff --git a/package.json b/package.json index d418e3e..6d86c04 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,8 @@ "scripts": { "test": "istanbul test ./node_modules/.bin/_mocha -- --reporter list test/*.js", "compile": "browserify src/index.js -s Bitcoin | uglifyjs > bitcoinjs-min.js" + }, + "dependencies": { + "crypto-js": "~3.1.2-2" } } diff --git a/src/address.js b/src/address.js index a4d5168..79720d4 100644 --- a/src/address.js +++ b/src/address.js @@ -1,5 +1,4 @@ var base58 = require('./base58'); -var Crypto = require('./crypto-js/crypto'); var conv = require('./convert'); var util = require('./util'); var mainnet = require('./network').mainnet.addressVersion; diff --git a/src/base58.js b/src/base58.js index 5390e7a..ec584c0 100644 --- a/src/base58.js +++ b/src/base58.js @@ -2,8 +2,11 @@ // https://en.bitcoin.it/wiki/Base58Check_encoding var BigInteger = require('./jsbn/jsbn'); -var Crypto = require('./crypto-js/crypto'); +var Crypto = require('crypto-js'); +var SHA256 = Crypto.SHA256; +var WordArray = Crypto.lib.WordArray; var conv = require('./convert'); +var util = require('./util'); var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; var base = BigInteger.valueOf(58); @@ -80,18 +83,15 @@ module.exports.decode = function (input) { module.exports.checkEncode = function(input, vbyte) { vbyte = vbyte || 0; - var front = [vbyte].concat(input); - var checksum = Crypto.SHA256(Crypto.SHA256(front, {asBytes: true}), {asBytes: true}) - .slice(0,4); - return module.exports.encode(front.concat(checksum)); + var front = [vbyte].concat(input) + return module.exports.encode(front.concat(getChecksum(front))); } module.exports.checkDecode = function(input) { var bytes = module.exports.decode(input), front = bytes.slice(0,bytes.length-4), back = bytes.slice(bytes.length-4); - var checksum = Crypto.SHA256(Crypto.SHA256(front,{asBytes: true}), {asBytes: true}) - .slice(0,4); + var checksum = getChecksum(front) if (""+checksum != ""+back) { throw new Error("Checksum failed"); } @@ -99,3 +99,11 @@ module.exports.checkDecode = function(input) { o.version = front[0]; return o; } + +function getChecksum(bytes) { + var wordArray = util.bytesToWordArray(bytes) + return conv.hexToBytes(SHA256(SHA256(wordArray)).toString()).slice(0,4); +} + +module.exports.getChecksum = getChecksum + diff --git a/src/ecdsa.js b/src/ecdsa.js index 54fda8b..0b4e3c2 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -3,7 +3,7 @@ var util = require('./util'); var SecureRandom = require('./jsbn/rng'); var BigInteger = require('./jsbn/jsbn'); var conv = require('./convert') -var Crypto = require('./crypto-js/crypto.js') +var HmacSHA256 = require('crypto-js/hmac-sha256'); var ECPointFp = require('./jsbn/ec').ECPointFp; @@ -39,16 +39,21 @@ function implShamirsTrick(P, k, Q, l) }; function deterministicGenerateK(hash,key) { - var v = []; - var k = []; - for (var i = 0;i < 32;i++) v.push(1); - for (var i = 0;i < 32;i++) k.push(0); - k = Crypto.HMAC(Crypto.SHA256,v.concat([0]).concat(key).concat(hash),k,{ asBytes: true }) - v = Crypto.HMAC(Crypto.SHA256,v,k,{ asBytes: true }) - k = Crypto.HMAC(Crypto.SHA256,v.concat([1]).concat(key).concat(hash),k,{ asBytes: true }) - v = Crypto.HMAC(Crypto.SHA256,v,k,{ asBytes: true }) - v = Crypto.HMAC(Crypto.SHA256,v,k,{ asBytes: true }) - return BigInteger.fromByteArrayUnsigned(v); + var vArr = []; + var kArr = []; + for (var i = 0;i < 32;i++) vArr.push(1); + for (var i = 0;i < 32;i++) kArr.push(0); + var v = util.bytesToWordArray(vArr) + var k = util.bytesToWordArray(kArr) + + k = HmacSHA256(util.bytesToWordArray(vArr.concat([0]).concat(key).concat(hash)), k) + v = HmacSHA256(v, k) + vArr = util.wordArrayToBytes(v) + k = HmacSHA256(util.bytesToWordArray(vArr.concat([1]).concat(key).concat(hash)), k) + v = HmacSHA256(v,k) + v = HmacSHA256(v,k) + vArr = util.wordArrayToBytes(v) + return BigInteger.fromByteArrayUnsigned(vArr); } var ECDSA = { diff --git a/src/eckey.js b/src/eckey.js index f6b907f..a729d89 100644 --- a/src/eckey.js +++ b/src/eckey.js @@ -1,7 +1,6 @@ var BigInteger = require('./jsbn/jsbn'); var sec = require('./jsbn/sec'); var base58 = require('./base58'); -var Crypto = require('./crypto-js/crypto'); var util = require('./util'); var conv = require('./convert'); var Address = require('./address'); diff --git a/src/hdwallet.js b/src/hdwallet.js index 8a65b1a..10d5a6b 100644 --- a/src/hdwallet.js +++ b/src/hdwallet.js @@ -3,7 +3,8 @@ var base58 = require('./base58.js') var assert = require('assert') var format = require('util').format var util = require('./util.js') -var Crypto = require('./crypto-js/crypto.js') +var Crypto = require('crypto-js'); +var HmacSHA512 = Crypto.HmacSHA512 var ECKey = require('./eckey.js').ECKey var ECPubKey = require('./eckey.js').ECPubKey var Address = require('./address.js') @@ -12,7 +13,8 @@ var Network = require('./network') var HDWallet = module.exports = function(seed, network) { if (seed === undefined) return - var I = Crypto.HMAC(Crypto.SHA512, seed, 'Bitcoin seed', { asBytes: true }) + var seedWords = util.bytesToWordArray(convert.stringToBytes(seed)) + var I = util.wordArrayToBytes(HmacSHA512(seedWords, 'Bitcoin seed')) this.chaincode = I.slice(32) this.network = network || 'mainnet' if(!Network.hasOwnProperty(this.network)) { @@ -32,10 +34,7 @@ function arrayEqual(a, b) { return !(a < b || a > b) } -HDWallet.getChecksum = function(buffer) { - assert.equal(buffer.length, HDWallet.LENGTH) - return Crypto.SHA256(Crypto.SHA256(buffer, { asBytes: true }), { asBytes: true }).slice(0, 4) -} +HDWallet.getChecksum = base58.getChecksum; HDWallet.fromMasterHex = function(hex) { var bytes = convert.hexToBytes(hex) @@ -188,6 +187,7 @@ HDWallet.prototype.derive = function(i) { , iBytes = util.numToBytes(i, 4).reverse() , cPar = this.chaincode , usePriv = i >= HDWallet.HIGHEST_BIT + , SHA512 = Crypto.algo.SHA512 if (usePriv) { assert(this.priv, 'Private derive on public key') @@ -195,12 +195,12 @@ HDWallet.prototype.derive = function(i) { // If 1, private derivation is used: // let I = HMAC-SHA512(Key = cpar, Data = 0x00 || kpar || i) [Note:] var kPar = this.priv.toBytes().slice(0, 32) - I = Crypto.HMAC(Crypto.SHA512, [0].concat(kPar, iBytes), cPar, { asBytes: true }) + I = util.HmacFromBytesToBytes(SHA512, [0].concat(kPar, iBytes), cPar) } else { // If 0, public derivation is used: // let I = HMAC-SHA512(Key = cpar, Data = χ(kpar*G) || i) var KPar = this.pub.toBytes(true) - I = Crypto.HMAC(Crypto.SHA512, KPar.concat(iBytes), cPar, { asBytes: true }) + I = util.HmacFromBytesToBytes(SHA512, KPar.concat(iBytes), cPar) } // Split I = IL || IR into two 32-byte sequences, IL and IR. @@ -239,3 +239,4 @@ HDWallet.prototype.getKeyVersion = function() { } HDWallet.prototype.toString = HDWallet.prototype.toBase58 + diff --git a/src/index.js b/src/index.js index 2aa97ee..375244f 100644 --- a/src/index.js +++ b/src/index.js @@ -31,7 +31,7 @@ module.exports = { ECPubKey: Key.ECPubKey, Message: require('./message'), BigInteger: require('./jsbn/jsbn'), - Crypto: require('./crypto-js/crypto'), + Crypto: require('crypto-js'), //should we expose this at all? Script: require('./script'), Opcode: require('./opcode'), Transaction: require('./transaction').Transaction, diff --git a/src/message.js b/src/message.js index b370f92..2c0f03e 100644 --- a/src/message.js +++ b/src/message.js @@ -1,6 +1,6 @@ /// Implements Bitcoin's feature for signing arbitrary messages. -var Crypto = require('./crypto-js/crypto'); +var SHA256 = require('crypto-js/sha256'); var ecdsa = require('./ecdsa'); var conv = require('./convert'); var util = require('./util'); @@ -24,7 +24,7 @@ Message.makeMagicMessage = function (message) { Message.getHash = function (message) { var buffer = Message.makeMagicMessage(message); - return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); + return util.wordArrayToBytes(SHA256(SHA256(util.bytesToWordArray(buffer)))); }; Message.signMessage = function (key, message, compressed) { diff --git a/src/transaction.js b/src/transaction.js index 6f7f15b..a9ba2e8 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -2,11 +2,11 @@ var BigInteger = require('./jsbn/jsbn'); var Script = require('./script'); var util = require('./util'); var conv = require('./convert'); -var Crypto = require('./crypto-js/crypto'); var Wallet = require('./wallet'); var ECKey = require('./eckey').ECKey; var ECDSA = require('./ecdsa'); var Address = require('./address'); +var Message = require('./message'); var Transaction = function (doc) { if (!(this instanceof Transaction)) { return new Transaction(doc); } @@ -207,9 +207,7 @@ function (connectedScript, inIndex, hashType) buffer = buffer.concat(util.numToBytes(parseInt(hashType),4)); - var hash1 = Crypto.SHA256(buffer, {asBytes: true}); - - return Crypto.SHA256(hash1, {asBytes: true}); + return Message.getHash(buffer) }; /** @@ -220,7 +218,7 @@ function (connectedScript, inIndex, hashType) Transaction.prototype.getHash = function () { var buffer = this.serialize(); - return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}).reverse(); + return Message.getHash(buffer).reverse() }; /** diff --git a/src/util.js b/src/util.js index 8d64662..bc61ec7 100644 --- a/src/util.js +++ b/src/util.js @@ -1,4 +1,8 @@ -var Crypto = require('./crypto-js/crypto'); +var Crypto = require('crypto-js'); +var RIPEMD160 = Crypto.RIPEMD160; +var SHA256 = Crypto.SHA256; +var HMAC= Crypto.algo.HMAC; +var WordArray = Crypto.lib.WordArray; /** * Create a byte array representing a number with the given length @@ -45,7 +49,15 @@ exports.wordsToBytes = function (words) { bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); } return bytes; -}, +} + +exports.bytesToWordArray = function (bytes) { + return new WordArray.init(exports.bytesToWords(bytes), bytes.length) +} + +exports.wordArrayToBytes = function (wordArray) { + return exports.wordsToBytes(wordArray.words) +} /** * Calculate RIPEMD160(SHA256(data)). @@ -54,7 +66,15 @@ exports.wordsToBytes = function (words) { * array. */ exports.sha256ripe160 = function (data) { - return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); + var wordArray = RIPEMD160(SHA256(exports.bytesToWordArray(data))) + return exports.wordArrayToBytes(wordArray) +} + + +exports.HmacFromBytesToBytes = function (hasher, message, key) { + var hmac = HMAC.create(hasher, exports.bytesToWordArray(key)) + hmac.update(exports.bytesToWordArray(message)) + return exports.wordArrayToBytes(hmac.finalize()) } exports.error = function(msg) { diff --git a/test/misc.js b/test/misc.js index 1ed0b8a..e1d0adc 100644 --- a/test/misc.js +++ b/test/misc.js @@ -3,13 +3,18 @@ var assert = require('assert'); var bitcoinjs = require('../'); var sec = require('../src/jsbn/sec'); var BigInteger = require('../src/jsbn/jsbn.js'); -var Crypto = require('../src/crypto-js/crypto.js'); +var SHA256 = require('crypto-js/sha256'); var SecureRandom = require('../src/jsbn/rng'); var rng = new SecureRandom(); var ecparams = sec('secp256k1'); var ECPointFp = bitcoinjs.ECPointFp; +var util = require('../src/util'); + +function sha256FromBytesToBytes(message){ + return util.wordArrayToBytes(SHA256(util.bytesToWordArray(message))) +} it('Keys & Key Management', function () { var p1 = bitcoinjs.Key().getPub()['export']('bytes'); @@ -36,9 +41,7 @@ it('Signing and Verifying', function () { assert.ok(s1.verify(BigInteger.ZERO, sig_a)); var message = new BigInteger(1024, rng).toByteArrayUnsigned(); - var hash = Crypto.SHA256(message, { - asBytes: true - }); + var hash = sha256FromBytesToBytes(message); var sig_b = s1.sign(hash); assert.ok(sig_b, 'Sign random string'); assert.ok(s1.verify(hash, sig_b)); @@ -50,9 +53,7 @@ it('Signing and Verifying', function () { '8a33f50d7cefb96a5dab897b5efcb99cbafb0d777cb83fc9b2115b69c0fa' + '3d82507b932b84e4'); - var hash2 = Crypto.SHA256(message2, { - asBytes: true - }); + var hash2 = sha256FromBytesToBytes(message2); var sig_c = bitcoinjs.convert.hexToBytes( '3044022038d9b8dd5c9fbf330565c1f51d72a59ba869aeb2c2001be959d3' +