Ryan X. Charles
11 years ago
17 changed files with 973 additions and 310 deletions
@ -1,349 +1,347 @@ |
|||
var BITCOIN_MAINNET_PUBLIC = 0x0488b21e; |
|||
var BITCOIN_MAINNET_PRIVATE = 0x0488ade4; |
|||
var BITCOIN_TESTNET_PUBLIC = 0x043587cf; |
|||
var BITCOIN_TESTNET_PRIVATE = 0x04358394; |
|||
var DOGECOIN_MAINNET_PUBLIC = 0x02facafd; |
|||
var DOGECOIN_MAINNET_PRIVATE = 0x02fac398; |
|||
var DOGECOIN_TESTNET_PUBLIC = 0x0432a9a8; |
|||
var DOGECOIN_TESTNET_PRIVATE = 0x0432a243; |
|||
var LITECOIN_MAINNET_PUBLIC = 0x019da462; |
|||
var LITECOIN_MAINNET_PRIVATE = 0x019d9cfe; |
|||
var LITECOIN_TESTNET_PUBLIC = 0x0436f6e1; |
|||
var LITECOIN_TESTNET_PRIVATE = 0x0436ef7d; |
|||
var imports = require('soop').imports(); |
|||
var base58 = imports.base58 || require('base58-native').base58; |
|||
var coinUtil = imports.coinUtil || require('./util/util'); |
|||
var Key = imports.Key || require('./Key'); |
|||
var Point = imports.Point || require('./Point'); |
|||
var bignum = imports.bignum || require('bignum'); |
|||
var crypto = require('crypto'); |
|||
var networks = require('./networks'); |
|||
|
|||
var secp256k1_n = new bignum("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); |
|||
var secp256k1_Gx = new bignum("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16); |
|||
|
|||
var BIP32 = function(bytes) { |
|||
// decode base58
|
|||
if( typeof bytes === "string" ) { |
|||
var decoded = Bitcoin.Base58.decode(bytes); |
|||
if( decoded.length != 82 ) throw new Error("Not enough data"); |
|||
var checksum = decoded.slice(78, 82); |
|||
bytes = decoded.slice(0, 78); |
|||
|
|||
var hash = Crypto.SHA256( Crypto.SHA256( bytes, { asBytes: true } ), { asBytes: true } ); |
|||
|
|||
if( hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3] ) { |
|||
throw new Error("Invalid checksum"); |
|||
} |
|||
if (bytes == 'mainnet' || bytes == 'livenet') |
|||
this.version = networks['livenet'].bip32private; |
|||
else if (bytes == 'testnet') |
|||
this.version = networks['testnet'].bip32private; |
|||
|
|||
if (bytes == 'mainnet' || bytes == 'livenet' || bytes == 'testnet') { |
|||
this.depth = 0x00; |
|||
this.parentFingerprint = new Buffer([0, 0, 0, 0]); |
|||
this.childIndex = new Buffer([0, 0, 0, 0]); |
|||
this.chainCode = Key.generateSync().private; |
|||
this.eckey = Key.generateSync(); |
|||
this.hasPrivateKey = true; |
|||
this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); |
|||
this.buildExtendedPublicKey(); |
|||
this.buildExtendedPrivateKey(); |
|||
return; |
|||
} |
|||
|
|||
// decode base58
|
|||
if (typeof bytes === "string") { |
|||
var decoded = base58.decode(bytes); |
|||
if (decoded.length != 82) |
|||
throw new Error("Not enough data"); |
|||
var checksum = decoded.slice(78, 82); |
|||
bytes = decoded.slice(0, 78); |
|||
|
|||
var hash = coinUtil.sha256(coinUtil.sha256(bytes)); |
|||
|
|||
if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) { |
|||
throw new Error("Invalid checksum"); |
|||
} |
|||
} |
|||
|
|||
if( bytes !== undefined ) |
|||
this.init_from_bytes(bytes); |
|||
if (bytes !== undefined) |
|||
this.initFromBytes(bytes); |
|||
} |
|||
|
|||
BIP32.prototype.init_from_bytes = function(bytes) { |
|||
// Both pub and private extended keys are 78 bytes
|
|||
if( bytes.length != 78 ) throw new Error("not enough data"); |
|||
|
|||
this.version = u32(bytes.slice(0, 4)); |
|||
this.depth = u8 (bytes.slice(4, 5)); |
|||
this.parent_fingerprint = bytes.slice(5, 9); |
|||
this.child_index = u32(bytes.slice(9, 13)); |
|||
this.chain_code = bytes.slice(13, 45); |
|||
|
|||
var key_bytes = bytes.slice(45, 78); |
|||
|
|||
var is_private = |
|||
(this.version == BITCOIN_MAINNET_PRIVATE || |
|||
this.version == BITCOIN_TESTNET_PRIVATE || |
|||
this.version == DOGECOIN_MAINNET_PRIVATE || |
|||
this.version == DOGECOIN_TESTNET_PRIVATE || |
|||
this.version == LITECOIN_MAINNET_PRIVATE || |
|||
this.version == LITECOIN_TESTNET_PRIVATE ); |
|||
|
|||
var is_public = |
|||
(this.version == BITCOIN_MAINNET_PUBLIC || |
|||
this.version == BITCOIN_TESTNET_PUBLIC || |
|||
this.version == DOGECOIN_MAINNET_PUBLIC || |
|||
this.version == DOGECOIN_TESTNET_PUBLIC || |
|||
this.version == LITECOIN_MAINNET_PUBLIC || |
|||
this.version == LITECOIN_TESTNET_PUBLIC ); |
|||
|
|||
if( is_private && key_bytes[0] == 0 ) { |
|||
this.eckey = new Bitcoin.ECKey(key_bytes.slice(1, 33)); |
|||
this.eckey.setCompressed(true); |
|||
|
|||
var ecparams = getSECCurveByName("secp256k1"); |
|||
var pt = ecparams.getG().multiply(this.eckey.priv); |
|||
this.eckey.pub = pt; |
|||
this.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(this.eckey.pub.getEncoded(true)); |
|||
this.has_private_key = true; |
|||
} else if( is_public && (key_bytes[0] == 0x02 || key_bytes[0] == 0x03) ) { |
|||
this.eckey = new Bitcoin.ECKey(); |
|||
this.eckey.pub = decompress_pubkey(key_bytes); |
|||
this.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(this.eckey.pub.getEncoded(true)); |
|||
this.eckey.setCompressed(true); |
|||
this.has_private_key = false; |
|||
} else { |
|||
throw new Error("Invalid key"); |
|||
} |
|||
|
|||
this.build_extended_public_key(); |
|||
this.build_extended_private_key(); |
|||
BIP32.seed = function(bytes, network) { |
|||
if (!network) |
|||
return false; |
|||
|
|||
if (!Buffer.isBuffer(bytes)) |
|||
bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex
|
|||
if (bytes.length < 128/8) |
|||
return false; //need more entropy
|
|||
var hash = coinUtil.sha512hmac(bytes, new Buffer("Bitcoin seed")); |
|||
|
|||
var bip32 = new BIP32(); |
|||
bip32.depth = 0x00; |
|||
bip32.parentFingerprint = new Buffer([0, 0, 0, 0]); |
|||
bip32.childIndex = new Buffer([0, 0, 0, 0]); |
|||
bip32.chainCode = hash.slice(32, 64); |
|||
bip32.version = networks[network].bip32private; |
|||
bip32.eckey = new Key(); |
|||
bip32.eckey.private = hash.slice(0, 32); |
|||
bip32.eckey.regenerateSync(); |
|||
bip32.hasPrivateKey = true; |
|||
bip32.pubKeyHash = coinUtil.sha256ripe160(bip32.eckey.public); |
|||
|
|||
bip32.buildExtendedPublicKey(); |
|||
bip32.buildExtendedPrivateKey(); |
|||
|
|||
return bip32; |
|||
}; |
|||
|
|||
BIP32.prototype.initFromBytes = function(bytes) { |
|||
// Both pub and private extended keys are 78 bytes
|
|||
if(bytes.length != 78) throw new Error("not enough data"); |
|||
|
|||
this.version = u32(bytes.slice(0, 4)); |
|||
this.depth = u8(bytes.slice(4, 5)); |
|||
this.parentFingerprint = bytes.slice(5, 9); |
|||
this.childIndex = u32(bytes.slice(9, 13)); |
|||
this.chainCode = bytes.slice(13, 45); |
|||
|
|||
var keyBytes = bytes.slice(45, 78); |
|||
|
|||
var isPrivate = |
|||
(this.version == networks['livenet'].bip32private || |
|||
this.version == networks['testnet'].bip32private ); |
|||
|
|||
var isPublic = |
|||
(this.version == networks['livenet'].bip32public || |
|||
this.version == networks['testnet'].bip32public ); |
|||
|
|||
if (isPrivate && keyBytes[0] == 0) { |
|||
this.eckey = new Key(); |
|||
this.eckey.private = keyBytes.slice(1, 33); |
|||
this.eckey.compressed = true; |
|||
this.eckey.regenerateSync(); |
|||
this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); |
|||
this.hasPrivateKey = true; |
|||
} else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) { |
|||
this.eckey = new Key(); |
|||
this.eckey.public = keyBytes; |
|||
this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); |
|||
this.hasPrivateKey = false; |
|||
} else { |
|||
throw new Error("Invalid key"); |
|||
} |
|||
|
|||
this.buildExtendedPublicKey(); |
|||
this.buildExtendedPrivateKey(); |
|||
} |
|||
|
|||
BIP32.prototype.build_extended_public_key = function() { |
|||
this.extended_public_key = []; |
|||
|
|||
var v = null; |
|||
switch(this.version) { |
|||
case BITCOIN_MAINNET_PUBLIC: |
|||
case BITCOIN_MAINNET_PRIVATE: |
|||
v = BITCOIN_MAINNET_PUBLIC; |
|||
break; |
|||
case BITCOIN_TESTNET_PUBLIC: |
|||
case BITCOIN_TESTNET_PRIVATE: |
|||
v = BITCOIN_TESTNET_PUBLIC; |
|||
break; |
|||
case DOGECOIN_MAINNET_PUBLIC: |
|||
case DOGECOIN_MAINNET_PRIVATE: |
|||
v = DOGECOIN_MAINNET_PUBLIC; |
|||
break; |
|||
case DOGECOIN_TESTNET_PUBLIC: |
|||
case DOGECOIN_TESTNET_PRIVATE: |
|||
v = DOGECOIN_TESTNET_PUBLIC; |
|||
break; |
|||
case LITECOIN_MAINNET_PUBLIC: |
|||
case LITECOIN_MAINNET_PRIVATE: |
|||
v = LITECOIN_MAINNET_PUBLIC; |
|||
break; |
|||
case LITECOIN_TESTNET_PUBLIC: |
|||
case LITECOIN_TESTNET_PRIVATE: |
|||
v = LITECOIN_TESTNET_PUBLIC; |
|||
break; |
|||
default: |
|||
throw new Error("Unknown version"); |
|||
} |
|||
|
|||
// Version
|
|||
this.extended_public_key.push(v >> 24); |
|||
this.extended_public_key.push((v >> 16) & 0xff); |
|||
this.extended_public_key.push((v >> 8) & 0xff); |
|||
this.extended_public_key.push(v & 0xff); |
|||
|
|||
// Depth
|
|||
this.extended_public_key.push(this.depth); |
|||
|
|||
// Parent fingerprint
|
|||
this.extended_public_key = this.extended_public_key.concat(this.parent_fingerprint); |
|||
|
|||
// Child index
|
|||
this.extended_public_key.push(this.child_index >>> 24); |
|||
this.extended_public_key.push((this.child_index >>> 16) & 0xff); |
|||
this.extended_public_key.push((this.child_index >>> 8) & 0xff); |
|||
this.extended_public_key.push(this.child_index & 0xff); |
|||
|
|||
// Chain code
|
|||
this.extended_public_key = this.extended_public_key.concat(this.chain_code); |
|||
|
|||
// Public key
|
|||
this.extended_public_key = this.extended_public_key.concat(this.eckey.pub.getEncoded(true)); |
|||
BIP32.prototype.buildExtendedPublicKey = function() { |
|||
this.extendedPublicKey = new Buffer([]); |
|||
|
|||
var v = null; |
|||
switch(this.version) { |
|||
case networks['livenet'].bip32public: |
|||
case networks['livenet'].bip32private: |
|||
v = networks['livenet'].bip32public; |
|||
break; |
|||
case networks['testnet'].bip32public: |
|||
case networks['testnet'].bip32private: |
|||
v = networks['testnet'].bip32public; |
|||
break; |
|||
default: |
|||
throw new Error("Unknown version"); |
|||
} |
|||
|
|||
// Version
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([v >> 24])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([(v >> 16) & 0xff])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([(v >> 8) & 0xff])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([v & 0xff])]); |
|||
|
|||
// Depth
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([this.depth])]); |
|||
|
|||
// Parent fingerprint
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, this.parentFingerprint]); |
|||
|
|||
// Child index
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([this.childIndex >>> 24])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([(this.childIndex >>> 16) & 0xff])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([(this.childIndex >>> 8) & 0xff])]); |
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, new Buffer([this.childIndex & 0xff])]); |
|||
|
|||
// Chain code
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, this.chainCode]); |
|||
|
|||
// Public key
|
|||
this.extendedPublicKey = Buffer.concat([this.extendedPublicKey, this.eckey.public]); |
|||
} |
|||
|
|||
BIP32.prototype.extended_public_key_string = function(format) { |
|||
if( format === undefined || format === "base58" ) { |
|||
var hash = Crypto.SHA256( Crypto.SHA256( this.extended_public_key, { asBytes: true } ), { asBytes: true } ); |
|||
var checksum = hash.slice(0, 4); |
|||
var data = this.extended_public_key.concat(checksum); |
|||
return Bitcoin.Base58.encode(data); |
|||
} else if( format === "hex" ) { |
|||
return Crypto.util.bytesToHex(this.extended_public_key); |
|||
} else { |
|||
throw new Error("bad format"); |
|||
} |
|||
BIP32.prototype.extendedPublicKeyString = function(format) { |
|||
if (format === undefined || format === "base58") { |
|||
var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPublicKey)); |
|||
var checksum = hash.slice(0, 4); |
|||
var data = Buffer.concat([this.extendedPublicKey, checksum]); |
|||
return base58.encode(data); |
|||
} else if (format === "hex") { |
|||
return this.extendedPublicKey.toString('hex');; |
|||
} else { |
|||
throw new Error("bad format"); |
|||
} |
|||
} |
|||
|
|||
BIP32.prototype.build_extended_private_key = function() { |
|||
if( !this.has_private_key ) return; |
|||
this.extended_private_key = []; |
|||
BIP32.prototype.buildExtendedPrivateKey = function() { |
|||
if (!this.hasPrivateKey) return; |
|||
this.extendedPrivateKey = new Buffer([]); |
|||
|
|||
var v = this.version; |
|||
var v = this.version; |
|||
|
|||
// Version
|
|||
this.extended_private_key.push(v >> 24); |
|||
this.extended_private_key.push((v >> 16) & 0xff); |
|||
this.extended_private_key.push((v >> 8) & 0xff); |
|||
this.extended_private_key.push(v & 0xff); |
|||
// Version
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([v >> 24])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([(v >> 16) & 0xff])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([(v >> 8) & 0xff])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([v & 0xff])]); |
|||
|
|||
// Depth
|
|||
this.extended_private_key.push(this.depth); |
|||
// Depth
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([this.depth])]); |
|||
|
|||
// Parent fingerprint
|
|||
this.extended_private_key = this.extended_private_key.concat(this.parent_fingerprint); |
|||
// Parent fingerprint
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, this.parentFingerprint]); |
|||
|
|||
// Child index
|
|||
this.extended_private_key.push(this.child_index >>> 24); |
|||
this.extended_private_key.push((this.child_index >>> 16) & 0xff); |
|||
this.extended_private_key.push((this.child_index >>> 8) & 0xff); |
|||
this.extended_private_key.push(this.child_index & 0xff); |
|||
// Child index
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([this.childIndex >>> 24])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([(this.childIndex >>> 16) & 0xff])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([(this.childIndex >>> 8) & 0xff])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([this.childIndex & 0xff])]); |
|||
|
|||
// Chain code
|
|||
this.extended_private_key = this.extended_private_key.concat(this.chain_code); |
|||
// Chain code
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, this.chainCode]); |
|||
|
|||
// Private key
|
|||
this.extended_private_key.push(0); |
|||
this.extended_private_key = this.extended_private_key.concat(this.eckey.priv.toByteArrayUnsigned()); |
|||
// Private key
|
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, new Buffer([0])]); |
|||
this.extendedPrivateKey = Buffer.concat([this.extendedPrivateKey, this.eckey.private]); |
|||
} |
|||
|
|||
BIP32.prototype.extended_private_key_string = function(format) { |
|||
if( format === undefined || format === "base58" ) { |
|||
var hash = Crypto.SHA256( Crypto.SHA256( this.extended_private_key, { asBytes: true } ), { asBytes: true } ); |
|||
var checksum = hash.slice(0, 4); |
|||
var data = this.extended_private_key.concat(checksum); |
|||
return Bitcoin.Base58.encode(data); |
|||
} else if( format === "hex" ) { |
|||
return Crypto.util.bytesToHex(this.extended_private_key); |
|||
} else { |
|||
throw new Error("bad format"); |
|||
} |
|||
BIP32.prototype.extendedPrivateKeyString = function(format) { |
|||
if (format === undefined || format === "base58") { |
|||
var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPrivateKey)); |
|||
var checksum = hash.slice(0, 4); |
|||
var data = Buffer.concat([this.extendedPrivateKey, checksum]); |
|||
return base58.encode(data); |
|||
} else if (format === "hex") { |
|||
return this.extendedPrivateKey.toString('hex'); |
|||
} else { |
|||
throw new Error("bad format"); |
|||
} |
|||
} |
|||
|
|||
|
|||
BIP32.prototype.derive = function(path) { |
|||
var e = path.split('/'); |
|||
|
|||
// Special cases:
|
|||
if( path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'' ) return this; |
|||
|
|||
var bip32 = this; |
|||
for( var i in e ) { |
|||
var c = e[i]; |
|||
var e = path.split('/'); |
|||
|
|||
if( i == 0 ) { |
|||
if( c != 'm' ) throw new Error("invalid path"); |
|||
continue; |
|||
} |
|||
// Special cases:
|
|||
if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'') |
|||
return this; |
|||
|
|||
var use_private = (c.length > 1) && (c[c.length-1] == '\''); |
|||
var child_index = parseInt(use_private ? c.slice(0, c.length - 1) : c) & 0x7fffffff; |
|||
var bip32 = this; |
|||
for (var i in e) { |
|||
var c = e[i]; |
|||
|
|||
if( use_private ) |
|||
child_index += 0x80000000; |
|||
|
|||
bip32 = bip32.derive_child(child_index); |
|||
if (i == 0 ) { |
|||
if (c != 'm') throw new Error("invalid path"); |
|||
continue; |
|||
} |
|||
|
|||
return bip32; |
|||
} |
|||
|
|||
BIP32.prototype.derive_child = function(i) { |
|||
var ib = []; |
|||
ib.push( (i >> 24) & 0xff ); |
|||
ib.push( (i >> 16) & 0xff ); |
|||
ib.push( (i >> 8) & 0xff ); |
|||
ib.push( i & 0xff ); |
|||
|
|||
var use_private = (i & 0x80000000) != 0; |
|||
var ecparams = getSECCurveByName("secp256k1"); |
|||
var usePrivate = (c.length > 1) && (c[c.length-1] == '\''); |
|||
var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff; |
|||
|
|||
var is_private = |
|||
(this.version == BITCOIN_MAINNET_PRIVATE || |
|||
this.version == BITCOIN_TESTNET_PRIVATE || |
|||
this.version == DOGECOIN_MAINNET_PRIVATE || |
|||
this.version == DOGECOIN_TESTNET_PRIVATE || |
|||
this.version == LITECOIN_MAINNET_PRIVATE || |
|||
this.version == LITECOIN_TESTNET_PRIVATE); |
|||
if (usePrivate) |
|||
childIndex += 0x80000000; |
|||
|
|||
if( use_private && (!this.has_private_key || !is_private) ) throw new Error("Cannot do private key derivation without private key"); |
|||
bip32 = bip32.deriveChild(childIndex); |
|||
} |
|||
|
|||
var ret = null; |
|||
if( this.has_private_key ) { |
|||
var data = null; |
|||
return bip32; |
|||
} |
|||
|
|||
if( use_private ) { |
|||
data = [0].concat(this.eckey.priv.toByteArrayUnsigned()).concat(ib); |
|||
} else { |
|||
data = this.eckey.pub.getEncoded(true).concat(ib); |
|||
} |
|||
BIP32.prototype.deriveChild = function(i) { |
|||
var ib = []; |
|||
ib.push((i >> 24) & 0xff); |
|||
ib.push((i >> 16) & 0xff); |
|||
ib.push((i >> 8) & 0xff); |
|||
ib.push(i & 0xff); |
|||
ib = new Buffer(ib); |
|||
|
|||
var j = new jsSHA(Crypto.util.bytesToHex(data), 'HEX'); |
|||
var hash = j.getHMAC(Crypto.util.bytesToHex(this.chain_code), "HEX", "SHA-512", "HEX"); |
|||
var il = new BigInteger(hash.slice(0, 64), 16); |
|||
var ir = Crypto.util.hexToBytes(hash.slice(64, 128)); |
|||
var usePrivate = (i & 0x80000000) != 0; |
|||
|
|||
// ki = IL + kpar (mod n).
|
|||
var curve = ecparams.getCurve(); |
|||
var k = il.add(this.eckey.priv).mod(ecparams.getN()); |
|||
var isPrivate = |
|||
(this.version == networks['livenet'].bip32private || |
|||
this.version == networks['testnet'].bip32private ); |
|||
|
|||
ret = new BIP32(); |
|||
ret.chain_code = ir; |
|||
if (usePrivate && (!this.hasPrivateKey || !isPrivate)) |
|||
throw new Error("Cannot do private key derivation without private key"); |
|||
|
|||
ret.eckey = new Bitcoin.ECKey(k.toByteArrayUnsigned()); |
|||
ret.eckey.pub = ret.eckey.getPubPoint(); |
|||
ret.has_private_key = true; |
|||
var ret = null; |
|||
if (this.hasPrivateKey) { |
|||
var data = null; |
|||
|
|||
if (usePrivate) { |
|||
data = Buffer.concat([new Buffer([0]), this.eckey.private, ib]); |
|||
} else { |
|||
var data = this.eckey.pub.getEncoded(true).concat(ib); |
|||
var j = new jsSHA(Crypto.util.bytesToHex(data), 'HEX'); |
|||
var hash = j.getHMAC(Crypto.util.bytesToHex(this.chain_code), "HEX", "SHA-512", "HEX"); |
|||
var il = new BigInteger(hash.slice(0, 64), 16); |
|||
var ir = Crypto.util.hexToBytes(hash.slice(64, 128)); |
|||
|
|||
// Ki = (IL + kpar)*G = IL*G + Kpar
|
|||
var k = ecparams.getG().multiply(il).add(this.eckey.pub); |
|||
|
|||
ret = new BIP32(); |
|||
ret.chain_code = ir; |
|||
|
|||
ret.eckey = new Bitcoin.ECKey(); |
|||
ret.eckey.pub = k; |
|||
ret.has_private_key = false; |
|||
data = Buffer.concat([this.eckey.public, ib]); |
|||
} |
|||
|
|||
ret.child_index = i; |
|||
ret.parent_fingerprint = this.eckey.pubKeyHash.slice(0,4); |
|||
ret.version = this.version; |
|||
ret.depth = this.depth + 1; |
|||
|
|||
ret.eckey.setCompressed(true); |
|||
ret.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(ret.eckey.pub.getEncoded(true)); |
|||
|
|||
ret.build_extended_public_key(); |
|||
ret.build_extended_private_key(); |
|||
|
|||
return ret; |
|||
var hash = coinUtil.sha512hmac(data, this.chainCode); |
|||
var il = bignum.fromBuffer(hash.slice(0, 32), {size: 32}); |
|||
var ir = hash.slice(32, 64); |
|||
|
|||
// ki = IL + kpar (mod n).
|
|||
var priv = bignum.fromBuffer(this.eckey.private, {size: 32}); |
|||
var k = il.add(priv).mod(secp256k1_n); |
|||
|
|||
ret = new BIP32(); |
|||
ret.chainCode = ir; |
|||
|
|||
ret.eckey = new Key(); |
|||
ret.eckey.private = k.toBuffer({size: 32}); |
|||
ret.eckey.regenerateSync(); |
|||
ret.hasPrivateKey = true; |
|||
|
|||
} else { |
|||
var data = Buffer.concat([this.eckey.public, ib]); |
|||
var hash = coinUtil.sha512hmac(data, this.chainCode); |
|||
var il = bignum.fromBuffer(hash.slice(0, 32), {size: 32}); |
|||
var ir = hash.slice(32, 64); |
|||
|
|||
// Ki = (IL + kpar)*G = IL*G + Kpar
|
|||
var ilGkey = new Key(); |
|||
ilGkey.private = il.toBuffer({size: 32}); |
|||
ilGkey.regenerateSync(); |
|||
var ilG = Point.fromKey(ilGkey); |
|||
var oldkey = new Key(); |
|||
oldkey.public = this.eckey.public; |
|||
var Kpar = Point.fromKey(oldkey); |
|||
var newpub = Point.add(ilG, Kpar).toKey().public; |
|||
|
|||
ret = new BIP32(); |
|||
ret.chainCode = new Buffer(ir); |
|||
|
|||
var eckey = new Key(); |
|||
eckey.public = newpub; |
|||
ret.eckey = eckey; |
|||
ret.hasPrivateKey = false; |
|||
} |
|||
|
|||
ret.childIndex = i; |
|||
ret.parentFingerprint = this.pubKeyHash.slice(0,4); |
|||
ret.version = this.version; |
|||
ret.depth = this.depth + 1; |
|||
|
|||
ret.eckey.compressed = true; |
|||
ret.pubKeyHash = coinUtil.sha256ripe160(ret.eckey.public); |
|||
|
|||
ret.buildExtendedPublicKey(); |
|||
ret.buildExtendedPrivateKey(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
|
|||
function uint(f, size) { |
|||
if (f.length < size) |
|||
throw new Error("not enough data"); |
|||
var n = 0; |
|||
for (var i = 0; i < size; i++) { |
|||
n *= 256; |
|||
n += f[i]; |
|||
} |
|||
return n; |
|||
if (f.length < size) |
|||
throw new Error("not enough data"); |
|||
var n = 0; |
|||
for (var i = 0; i < size; i++) { |
|||
n *= 256; |
|||
n += f[i]; |
|||
} |
|||
return n; |
|||
} |
|||
|
|||
function u8(f) { return uint(f,1); } |
|||
function u16(f) { return uint(f,2); } |
|||
function u32(f) { return uint(f,4); } |
|||
function u64(f) { return uint(f,8); } |
|||
|
|||
function decompress_pubkey(key_bytes) { |
|||
var y_bit = u8(key_bytes.slice(0, 1)) & 0x01; |
|||
var ecparams = getSECCurveByName("secp256k1"); |
|||
|
|||
// build X
|
|||
var x = BigInteger.ZERO.clone(); |
|||
x.fromString(Crypto.util.bytesToHex(key_bytes.slice(1, 33)), 16); |
|||
|
|||
// get curve
|
|||
var curve = ecparams.getCurve(); |
|||
var a = curve.getA().toBigInteger(); |
|||
var b = curve.getB().toBigInteger(); |
|||
var p = curve.getQ(); |
|||
|
|||
// compute y^2 = x^3 + a*x + b
|
|||
var tmp = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p); |
|||
|
|||
// compute modular square root of y (mod p)
|
|||
var y = tmp.modSqrt(p); |
|||
|
|||
// flip sign if we need to
|
|||
if( (y[0] & 0x01) != y_bit ) { |
|||
y = y.multiply(new BigInteger("-1")).mod(p); |
|||
} |
|||
|
|||
return new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y)); |
|||
} |
|||
function u8(f) {return uint(f,1);} |
|||
function u16(f) {return uint(f,2);} |
|||
function u32(f) {return uint(f,4);} |
|||
function u64(f) {return uint(f,8);} |
|||
|
|||
module.exports = require('soop')(BIP32); |
|||
|
@ -0,0 +1,138 @@ |
|||
"use strict"; |
|||
|
|||
var imports = require('soop').imports(); |
|||
var Key = imports.Key || require('./Key'); |
|||
var bignum = imports.bignum || require('bignum'); |
|||
var assert = require('assert'); |
|||
|
|||
//browser
|
|||
if (!process.versions) { |
|||
var ECKey = require('./browser/vendor-bundle.js').ECKey; |
|||
var ECPointFp = require('./browser/vendor-bundle.js').ECPointFp; |
|||
var ECFieldElementFp = require('./browser/vendor-bundle.js').ECFieldElementFp; |
|||
var getSECCurveByName = require('./browser/vendor-bundle.js').getSECCurveByName; |
|||
var BigInteger = require('./browser/vendor-bundle.js').BigInteger; |
|||
var should = require('chai').should(); |
|||
} |
|||
|
|||
|
|||
//a point on the secp256k1 curve
|
|||
//x and y are bignums
|
|||
var Point = function(x, y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
}; |
|||
|
|||
Point.add = function(p1, p2) { |
|||
|
|||
//node
|
|||
if (process.versions) { |
|||
var key1 = p1.toKey(); |
|||
key1.compressed = false; |
|||
var key2 = p2.toKey(); |
|||
key2.compressed = false; |
|||
var pubKey = Key.addUncompressed(key1.public, key2.public); |
|||
var key = new Key(); |
|||
key.compressed = false; |
|||
key.public = pubKey; |
|||
key.compressed = true; |
|||
return Point.fromKey(key); |
|||
} |
|||
|
|||
//browser
|
|||
else { |
|||
var ecparams = getSECCurveByName('secp256k1'); |
|||
|
|||
var p1xhex = p1.x.toBuffer({size: 32}).toString('hex'); |
|||
var p1x = new BigInteger(p1xhex, 16); |
|||
var p1yhex = p1.y.toBuffer({size: 32}).toString('hex'); |
|||
var p1y = new BigInteger(p1yhex, 16); |
|||
var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x); |
|||
var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y); |
|||
var p1p = new ECPointFp(ecparams.getCurve(), p1px, p1py); |
|||
|
|||
var p2xhex = p2.x.toBuffer({size: 32}).toString('hex'); |
|||
var p2x = new BigInteger(p2xhex, 16); |
|||
var p2yhex = p2.y.toBuffer({size: 32}).toString('hex'); |
|||
var p2y = new BigInteger(p2yhex, 16); |
|||
var p2px = new ECFieldElementFp(ecparams.getCurve().getQ(), p2x); |
|||
var p2py = new ECFieldElementFp(ecparams.getCurve().getQ(), p2y); |
|||
var p2p = new ECPointFp(ecparams.getCurve(), p2px, p2py); |
|||
|
|||
var p = p1p.add(p2p); |
|||
|
|||
var point = new Point(); |
|||
var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned()); |
|||
point.x = bignum.fromBuffer(pointxbuf, {size: pointxbuf.length}); |
|||
assert(pointxbuf.length <= 32); |
|||
var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned()); |
|||
assert(pointybuf.length <= 32); |
|||
point.y = bignum.fromBuffer(pointybuf, {size: pointybuf.length}); |
|||
|
|||
return point; |
|||
} |
|||
|
|||
}; |
|||
|
|||
//convert the public key of a Key into a Point
|
|||
Point.fromKey = function(key) { |
|||
|
|||
//node
|
|||
if (process.versions) { |
|||
var point = new Point(); |
|||
var pubKeyBuf = new Buffer(key.public); |
|||
var key2 = new Key(); |
|||
key2.compressed = key.compressed; |
|||
key2.public = pubKeyBuf; |
|||
key2.compressed = false; |
|||
point.x = bignum.fromBuffer(key2.public.slice(1, 33), {size: 32}); |
|||
point.y = bignum.fromBuffer(key2.public.slice(33, 65), {size: 32}); |
|||
return point; |
|||
} |
|||
|
|||
//browser
|
|||
else { |
|||
var point = new Point(); |
|||
var pubKeyBuf = new Buffer(key.public); |
|||
var key2 = new ECKey(); |
|||
key2.setCompressed(key.compressed); |
|||
key2.setPub(Key.bufferToArray(pubKeyBuf)); |
|||
key2.setCompressed(false); |
|||
point.x = bignum.fromBuffer((new Buffer(key2.getPub())).slice(1, 33), {size: 32}); |
|||
point.y = bignum.fromBuffer((new Buffer(key2.getPub())).slice(33, 65), {size: 32}); |
|||
return point; |
|||
} |
|||
}; |
|||
|
|||
//convert the Point into the Key containing a compressed public key
|
|||
Point.prototype.toKey = function() { |
|||
|
|||
//node
|
|||
if (process.versions) { |
|||
var xbuf = this.x.toBuffer({size: 32}); |
|||
var ybuf = this.y.toBuffer({size: 32}); |
|||
var key = new Key(); |
|||
key.compressed = false; |
|||
var prefix = new Buffer([0x04]); |
|||
key.public = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong
|
|||
key.compressed = true; |
|||
return key; |
|||
} |
|||
|
|||
//browser
|
|||
else { |
|||
var xbuf = this.x.toBuffer({size: 32}); |
|||
var ybuf = this.y.toBuffer({size: 32}); |
|||
var key = new ECKey(); |
|||
key.setCompressed(false); |
|||
var prefix = new Buffer([0x04]); |
|||
var pub = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong
|
|||
key.setPub(Key.bufferToArray(pub)); |
|||
key.setCompressed(true); |
|||
var key2 = new Key(); |
|||
key2.public = new Buffer(key.getPub()); |
|||
return key2; |
|||
} |
|||
}; |
|||
|
|||
module.exports = require('soop')(Point); |
@ -0,0 +1,297 @@ |
|||
'use strict'; |
|||
|
|||
var chai = chai || require('chai'); |
|||
var should = chai.should(); |
|||
var bitcore = bitcore || require('../bitcore'); |
|||
var BIP32 = bitcore.BIP32; |
|||
|
|||
describe('BIP32', function() { |
|||
|
|||
//test vectors: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
|||
var vector1_master = '000102030405060708090a0b0c0d0e0f'; |
|||
var vector1_m_public = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8' |
|||
var vector1_m_private = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'; |
|||
var vector1_m0h_public = 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'; |
|||
var vector1_m0h_private = 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'; |
|||
var vector1_m0h1_public = 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'; |
|||
var vector1_m0h1_private = 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs'; |
|||
var vector1_m0h12h_public = 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'; |
|||
var vector1_m0h12h_private = 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'; |
|||
var vector1_m0h12h2_public = 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV'; |
|||
var vector1_m0h12h2_private = 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334'; |
|||
var vector1_m0h12h21000000000_public = 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy'; |
|||
var vector1_m0h12h21000000000_private = 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76'; |
|||
var vector2_master = 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'; |
|||
var vector2_m_public = 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'; |
|||
var vector2_m_private = 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U'; |
|||
var vector2_m0_public = 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH'; |
|||
var vector2_m0_private = 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt'; |
|||
var vector2_m02147483647h_public = 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a'; |
|||
var vector2_m02147483647h_private = 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9'; |
|||
var vector2_m02147483647h1_public = 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon'; |
|||
var vector2_m02147483647h1_private = 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef'; |
|||
var vector2_m02147483647h12147483646h_public = 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL'; |
|||
var vector2_m02147483647h12147483646h_private = 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc'; |
|||
var vector2_m02147483647h12147483646h2_public = 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt'; |
|||
var vector2_m02147483647h12147483646h2_private = 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j'; |
|||
|
|||
|
|||
it('should initialize the class', function() { |
|||
should.exist(BIP32); |
|||
}); |
|||
|
|||
it('should create a mainnet bip32', function() { |
|||
var bip32 = new BIP32('mainnet'); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should create a testnet bip32', function() { |
|||
var bip32 = new BIP32('testnet'); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should initialize test vector 1 from the extended public key', function() { |
|||
var bip32 = new BIP32(vector1_m_public); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should initialize test vector 1 from the extended private key', function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should get the extended public key from the extended private key for test vector 1', function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
bip32.extendedPublicKeyString().should.equal(vector1_m_public); |
|||
}); |
|||
|
|||
it("should get m/0' ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector1_m0h_private); |
|||
}); |
|||
|
|||
it("should get m/0' ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector1_m0h_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector1_m0h1_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector1_m0h1_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. public key from m/0' public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/1"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector1_m0h1_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector1_m0h12h_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector1_m0h12h_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector1_m0h12h2_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2'/2 ext. public key from m/0'/1/2' public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/2"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector1_m0h12h2_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector1_m0h12h2_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2/1000000000 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2/1000000000"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector1_m0h12h21000000000_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2/1000000000 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2/1000000000"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector1_m0h12h21000000000_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2'/2/1000000000 ext. public key from m/0'/1/2'/2 public key from test vector 1", function() { |
|||
var bip32 = new BIP32(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/1000000000"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector1_m0h12h21000000000_public); |
|||
}); |
|||
|
|||
it('should initialize test vector 2 from the extended public key', function() { |
|||
var bip32 = new BIP32(vector2_m_public); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should initialize test vector 2 from the extended private key', function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should get the extended public key from the extended private key for test vector 2', function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
bip32.extendedPublicKeyString().should.equal(vector2_m_public); |
|||
}); |
|||
|
|||
it("should get m/0 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector2_m0_private); |
|||
}); |
|||
|
|||
it("should get m/0 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector2_m0_public); |
|||
}); |
|||
|
|||
it("should get m/0 ext. public key from m public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/0"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector2_m0_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector2_m02147483647h_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector2_m02147483647h_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector2_m02147483647h1_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector2_m02147483647h1_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. public key from m/0/2147483647h public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/1"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector2_m02147483647h1_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector2_m02147483647h12147483646h_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector2_m02147483647h12147483646h_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'/2"); |
|||
should.exist(child); |
|||
child.extendedPrivateKeyString().should.equal(vector2_m02147483647h12147483646h2_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'/2"); |
|||
should.exist(child); |
|||
child.extendedPublicKeyString().should.equal(vector2_m02147483647h12147483646h2_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. public key from m/0/2147483647h/2147483646h public key from test vector 2", function() { |
|||
var bip32 = new BIP32(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
var child_pub = new BIP32(child.extendedPublicKeyString()); |
|||
var child2 = child_pub.derive("m/2"); |
|||
should.exist(child2); |
|||
child2.extendedPublicKeyString().should.equal(vector2_m02147483647h12147483646h2_public); |
|||
}); |
|||
|
|||
describe('#seed', function() { |
|||
|
|||
it('should initialize a new BIP32 correctly from test vector 1 seed', function() { |
|||
var hex = vector1_master; |
|||
var bip32 = BIP32.seed(hex, 'livenet'); |
|||
should.exist(bip32); |
|||
bip32.extendedPrivateKeyString().should.equal(vector1_m_private); |
|||
bip32.extendedPublicKeyString().should.equal(vector1_m_public); |
|||
}); |
|||
|
|||
it('should initialize a new BIP32 correctly from test vector 2 seed', function() { |
|||
var hex = vector2_master; |
|||
var bip32 = BIP32.seed(hex, 'livenet'); |
|||
should.exist(bip32); |
|||
bip32.extendedPrivateKeyString().should.equal(vector2_m_private); |
|||
bip32.extendedPublicKeyString().should.equal(vector2_m_public); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,69 @@ |
|||
'use strict'; |
|||
|
|||
var assert = require('assert'); |
|||
var chai = chai || require('chai'); |
|||
var bitcore = bitcore || require('../bitcore'); |
|||
var coinUtil = coinUtil || require('../util/util'); |
|||
var buffertools = require('buffertools'); |
|||
var bignum = require('bignum'); |
|||
|
|||
var should = chai.should(); |
|||
|
|||
var Point = bitcore.Point; |
|||
var Key = bitcore.Key; |
|||
|
|||
describe('Key', function() { |
|||
|
|||
it('should initialize the main object', function() { |
|||
should.exist(Point); |
|||
}); |
|||
|
|||
it('should be able to create instance', function() { |
|||
var p = new Point(); |
|||
should.exist(p); |
|||
}); |
|||
|
|||
it('should add these two points correctly', function() { |
|||
//these points are from one of the BIP32 test vectors
|
|||
var axhex = "69b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; |
|||
var ayhex = "eeedc91342b3c8982c1e676435780fe5f9d62f3f692e8d1512485d77fab35997"; |
|||
var a = new Point(bignum.fromBuffer((new Buffer(axhex, 'hex')), {size: 32}), bignum.fromBuffer((new Buffer(ayhex, 'hex')), {size: 32})); |
|||
var bxhex = "5a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"; |
|||
var byhex = "7f717885be239daadce76b568958305183ad616ff74ed4dc219a74c26d35f839"; |
|||
var b = new Point(bignum.fromBuffer((new Buffer(bxhex, 'hex')), {size: 32}), bignum.fromBuffer((new Buffer(byhex, 'hex')), {size: 32})); |
|||
var sxhex = "501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"; |
|||
var syhex = "008794c1df8131b9ad1e1359965b3f3ee2feef0866be693729772be14be881ab"; |
|||
var s = new Point(bignum.fromBuffer((new Buffer(sxhex, 'hex')), {size: 32}), bignum.fromBuffer((new Buffer(syhex, 'hex')), {size: 32})); |
|||
var sum = Point.add(a, b); |
|||
s.x.toBuffer({size: 32}).toString('hex').should.equal(sum.x.toBuffer({size: 32}).toString('hex')); |
|||
s.y.toBuffer({size: 32}).toString('hex').should.equal(sum.y.toBuffer({size: 32}).toString('hex')); |
|||
}); |
|||
|
|||
it('should convert a Point into the public key of a Key', function() { |
|||
var axhex = "69b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; |
|||
var axbuf = new Buffer(axhex, 'hex'); |
|||
var ayhex = "eeedc91342b3c8982c1e676435780fe5f9d62f3f692e8d1512485d77fab35997"; |
|||
var aybuf = new Buffer(ayhex, 'hex'); |
|||
var a = new Point(bignum.fromBuffer(axbuf, {size: 32}), bignum.fromBuffer(aybuf, {size: 32})); |
|||
|
|||
var pubKeyBufCompressedHex = "0369b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; |
|||
var key = new Key(); |
|||
key.public = new Buffer(pubKeyBufCompressedHex, 'hex'); |
|||
|
|||
key.public.toString('hex').should.equal(a.toKey().public.toString('hex')); |
|||
}); |
|||
|
|||
it('should convert the public key of a Key into a Point', function() { |
|||
var axhex = "69b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; |
|||
var ayhex = "eeedc91342b3c8982c1e676435780fe5f9d62f3f692e8d1512485d77fab35997"; |
|||
|
|||
var pubKeyBufCompressedHex = "0369b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; |
|||
var key = new Key(); |
|||
key.public = new Buffer(pubKeyBufCompressedHex, 'hex'); |
|||
|
|||
var point = Point.fromKey(key); |
|||
point.x.toBuffer({size: 32}).toString('hex').should.equal(axhex); |
|||
point.y.toBuffer({size: 32}).toString('hex').should.equal(ayhex); |
|||
}); |
|||
|
|||
}); |
Loading…
Reference in new issue