litecore-lib
Advanced tools
Comparing version 0.13.21 to 0.13.22
@@ -8,11 +8,11 @@ # Bitcoin Crypto | ||
## BN | ||
The `litecore.Crypto.BN` class contains a wrapper around [bn.js](https://github.com/indutny/bn.js), the bignum library used internally in litecore. | ||
The `litecore.crypto.BN` class contains a wrapper around [bn.js](https://github.com/indutny/bn.js), the bignum library used internally in litecore. | ||
## Point | ||
The `litecore.Crypto.Point` class contains a wrapper around the class Point of [elliptic.js](https://github.com/indutny/elliptic), the elliptic curve library used internally in litecore. | ||
The `litecore.crypto.Point` class contains a wrapper around the class Point of [elliptic.js](https://github.com/indutny/elliptic), the elliptic curve library used internally in litecore. | ||
## Hash | ||
The `litecore.Crypto.Hash` namespace contains a set of hashes and utilities. These are either the native `crypto` hash functions from `node.js` or their respective browser shims as provided by the `browserify` library. | ||
The `litecore.crypto.Hash` namespace contains a set of hashes and utilities. These are either the native `crypto` hash functions from `node.js` or their respective browser shims as provided by the `browserify` library. | ||
## ECDSA | ||
`litecore.Crypto.ECDSA` contains a pure JavaScript implementation of the elliptic curve DSA signature scheme based on [elliptic.js](https://github.com/indutny/elliptic). | ||
`litecore.crypto.ECDSA` contains a pure JavaScript implementation of the elliptic curve DSA signature scheme based on [elliptic.js](https://github.com/indutny/elliptic). |
@@ -18,3 +18,3 @@ # HDKeys | ||
var retrieved = new HDPrivateKey('xpriv...'); | ||
var derived = hdPrivateKey.derive("m/0'"); | ||
var derived = hdPrivateKey.derive("m/0'"); // see deprecation warning for derive | ||
var derivedByNumber = hdPrivateKey.derive(1).derive(2, true); | ||
@@ -43,3 +43,12 @@ var derivedByArgument = hdPrivateKey.derive("m/1/2'"); | ||
var address = new Address(hdPublicKey.publicKey, Networks.livenet); | ||
var derivedAddress = new Address(hdPublicKey.derive(100).publicKey, Networks.testnet); | ||
var derivedAddress = new Address(hdPublicKey.derive(100).publicKey, Networks.testnet); // see deprecation warning for derive | ||
``` | ||
## Deprecation Warning for `HDPublicKey.derive()` and `HDPrivateKey.derive()` | ||
There was a bug that was discovered with derivation that would incorrectly calculate the child key against the [BIP32 specification](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki). | ||
The bug only affected hardened derivations using an extended private key, and did not affect public key derivation. It also did not affect every derivation and would happen 1 in 256 times where where the private key for the extended private key had a leading zero *(e.g. any private key less than or equal to '0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')*. The leading zero was not included in serialization before hashing to derive a child key, as it should have been. | ||
As a result, `HDPublicKey.derive()` and `HDPrivateKey.derive()` are now deprecated. These methods will throw an error in the next major release. | ||
`HDPublicKey.deriveChild()`, `HDPrivateKey.deriveChild()`, and `HDPrivateKey.deriveNonCompliantChild()` have been implemented as alternatives. Note that these new methods will not be officially supported until v1.0.0. `deriveNonCompliantChild` will derive using the non-BIP32 derivation and is equivalent to the buggy version, `derive`. The `deriveNonCompliantChild` method should not be used unless you're upgrading and need to maintain compatibility with the old derivation. |
@@ -1,2 +0,2 @@ | ||
# Litecore v0.1 | ||
# Bitcore v0.14 | ||
@@ -20,6 +20,6 @@ ## Principles | ||
* [Using Different Units](unit.md) | ||
* [Acknowledging and Requesting Payments: Litecoin URIs](uri.md) | ||
* [Acknowledging and Requesting Payments: Bitcoin URIs](uri.md) | ||
* [The Transaction Class](transaction.md) | ||
## Litecoin Internals | ||
## Bitcoin Internals | ||
* [Scripts](script.md) | ||
@@ -46,3 +46,3 @@ * [Block](block.md) | ||
* [Blockchain Explorers](https://github.com/bitpay/bitcore-explorers) | ||
* [Signed Messages](https://github.com/litecoin-project/litecore-message) | ||
* [Signed Messages](https://github.com/bitpay/bitcore-message) | ||
@@ -49,0 +49,0 @@ # Examples |
@@ -70,3 +70,2 @@ 'use strict'; | ||
// Internal usage, exposed for testing/advanced tweaking | ||
litecore._HDKeyCache = require('./lib/hdkeycache'); | ||
litecore.Transaction.sighash = require('./lib/transaction/sighash'); |
@@ -258,7 +258,12 @@ 'use strict'; | ||
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' | ||
* @param {boolean=} nestedWitness - if the address uses a nested p2sh witness | ||
* @return {Address} | ||
*/ | ||
Address.createMultisig = function(publicKeys, threshold, network) { | ||
Address.createMultisig = function(publicKeys, threshold, network, nestedWitness) { | ||
network = network || publicKeys[0].network || Networks.defaultNetwork; | ||
return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network); | ||
var redeemScript = Script.buildMultisigOut(publicKeys, threshold); | ||
if (nestedWitness) { | ||
return Address.payingTo(Script.buildWitnessMultisigOutFromScript(redeemScript), network); | ||
} | ||
return Address.payingTo(redeemScript, network); | ||
}; | ||
@@ -336,3 +341,2 @@ | ||
$.checkArgument(script instanceof Script, 'script must be instance of Script'); | ||
return Address.fromScriptHash(Hash.sha256ripemd160(script.toBuffer()), network); | ||
@@ -339,0 +343,0 @@ }; |
@@ -139,3 +139,3 @@ 'use strict'; | ||
var info = {}; | ||
info.version = br.readUInt32LE(); | ||
info.version = br.readInt32LE(); | ||
info.prevHash = br.read(32); | ||
@@ -195,3 +195,3 @@ info.merkleRoot = br.read(32); | ||
} | ||
bw.writeUInt32LE(this.version); | ||
bw.writeInt32LE(this.version); | ||
bw.write(this.prevHash); | ||
@@ -198,0 +198,0 @@ bw.write(this.merkleRoot); |
@@ -91,3 +91,3 @@ 'use strict'; | ||
$.checkArgument(BufferUtil.isBuffer(buf)); | ||
return Scrypt(buf, buf, 1024, 1, 1, 32).reverse(); | ||
return BufferUtil.reverse(Scrypt(buf, buf, 1024, 1, 1, 32)); | ||
}; |
@@ -86,2 +86,8 @@ 'use strict'; | ||
BufferReader.prototype.readInt32LE = function() { | ||
var val = this.buf.readInt32LE(this.pos); | ||
this.pos = this.pos + 4; | ||
return val; | ||
}; | ||
BufferReader.prototype.readUInt64BEBN = function() { | ||
@@ -88,0 +94,0 @@ var buf = this.buf.slice(this.pos, this.pos + 8); |
@@ -14,3 +14,2 @@ 'use strict'; | ||
var Network = require('./networks'); | ||
var HDKeyCache = require('./hdkeycache'); | ||
var Point = require('./crypto/point'); | ||
@@ -132,2 +131,5 @@ var PrivateKey = require('./privatekey'); | ||
/** | ||
* WARNING: This method is deprecated. Use deriveChild or deriveNonCompliantChild instead. This is not BIP32 compliant | ||
* | ||
* | ||
* Get a derived child based on a string or number. | ||
@@ -156,2 +158,35 @@ * | ||
HDPrivateKey.prototype.derive = function(arg, hardened) { | ||
return this.deriveNonCompliantChild(arg, hardened); | ||
}; | ||
/** | ||
* WARNING: This method will not be officially supported until v1.0.0. | ||
* | ||
* | ||
* Get a derived child based on a string or number. | ||
* | ||
* If the first argument is a string, it's parsed as the full path of | ||
* derivation. Valid values for this argument include "m" (which returns the | ||
* same private key), "m/0/1/40/2'/1000", where the ' quote means a hardened | ||
* derivation. | ||
* | ||
* If the first argument is a number, the child with that index will be | ||
* derived. If the second argument is truthy, the hardened version will be | ||
* derived. See the example usage for clarification. | ||
* | ||
* WARNING: The `nonCompliant` option should NOT be used, except for older implementation | ||
* that used a derivation strategy that used a non-zero padded private key. | ||
* | ||
* @example | ||
* ```javascript | ||
* var parent = new HDPrivateKey('xprv...'); | ||
* var child_0_1_2h = parent.deriveChild(0).deriveChild(1).deriveChild(2, true); | ||
* var copy_of_child_0_1_2h = parent.deriveChild("m/0/1/2'"); | ||
* assert(child_0_1_2h.xprivkey === copy_of_child_0_1_2h); | ||
* ``` | ||
* | ||
* @param {string|number} arg | ||
* @param {boolean?} hardened | ||
*/ | ||
HDPrivateKey.prototype.deriveChild = function(arg, hardened) { | ||
if (_.isNumber(arg)) { | ||
@@ -166,3 +201,29 @@ return this._deriveWithNumber(arg, hardened); | ||
HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { | ||
/** | ||
* WARNING: This method will not be officially supported until v1.0.0 | ||
* | ||
* | ||
* WARNING: If this is a new implementation you should NOT use this method, you should be using | ||
* `derive` instead. | ||
* | ||
* This method is explicitly for use and compatibility with an implementation that | ||
* was not compliant with BIP32 regarding the derivation algorithm. The private key | ||
* must be 32 bytes hashing, and this implementation will use the non-zero padded | ||
* serialization of a private key, such that it's still possible to derive the privateKey | ||
* to recover those funds. | ||
* | ||
* @param {string|number} arg | ||
* @param {boolean?} hardened | ||
*/ | ||
HDPrivateKey.prototype.deriveNonCompliantChild = function(arg, hardened) { | ||
if (_.isNumber(arg)) { | ||
return this._deriveWithNumber(arg, hardened, true); | ||
} else if (_.isString(arg)) { | ||
return this._deriveFromString(arg, true); | ||
} else { | ||
throw new hdErrors.InvalidDerivationArgument(arg); | ||
} | ||
}; | ||
HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonCompliant) { | ||
/* jshint maxstatements: 20 */ | ||
@@ -179,11 +240,14 @@ /* jshint maxcomplexity: 10 */ | ||
var cached = HDKeyCache.get(this.xprivkey, index, hardened); | ||
if (cached) { | ||
return cached; | ||
} | ||
var indexBuffer = BufferUtil.integerAsBuffer(index); | ||
var data; | ||
if (hardened) { | ||
data = BufferUtil.concat([new buffer.Buffer([0]), this.privateKey.toBuffer(), indexBuffer]); | ||
if (hardened && nonCompliant) { | ||
// The private key serialization in this case will not be exactly 32 bytes and can be | ||
// any value less, and the value is not zero-padded. | ||
var nonZeroPadded = this.privateKey.bn.toBuffer(); | ||
data = BufferUtil.concat([new buffer.Buffer([0]), nonZeroPadded, indexBuffer]); | ||
} else if (hardened) { | ||
// This will use a 32 byte zero padded serialization of the private key | ||
var privateKeyBuffer = this.privateKey.bn.toBuffer({size: 32}); | ||
assert(privateKeyBuffer.length === 32, 'length of private key buffer is expected to be 32 bytes'); | ||
data = BufferUtil.concat([new buffer.Buffer([0]), privateKeyBuffer, indexBuffer]); | ||
} else { | ||
@@ -202,2 +266,7 @@ data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); | ||
if (!PrivateKey.isValid(privateKey)) { | ||
// Index at this point is already hardened, we can pass null as the hardened arg | ||
return this._deriveWithNumber(index + 1, null, nonCompliant); | ||
} | ||
var derived = new HDPrivateKey({ | ||
@@ -211,7 +280,7 @@ network: this.network, | ||
}); | ||
HDKeyCache.set(this.xprivkey, index, hardened, derived); | ||
return derived; | ||
}; | ||
HDPrivateKey.prototype._deriveFromString = function(path) { | ||
HDPrivateKey.prototype._deriveFromString = function(path, nonCompliant) { | ||
if (!HDPrivateKey.isValidPath(path)) { | ||
@@ -223,3 +292,3 @@ throw new hdErrors.InvalidPath(path); | ||
var derived = indexes.reduce(function(prev, index) { | ||
return prev._deriveWithNumber(index); | ||
return prev._deriveWithNumber(index, null, nonCompliant); | ||
}, this); | ||
@@ -226,0 +295,0 @@ |
@@ -11,3 +11,2 @@ 'use strict'; | ||
var HDPrivateKey = require('./hdprivatekey'); | ||
var HDKeyCache = require('./hdkeycache'); | ||
var Network = require('./networks'); | ||
@@ -91,2 +90,5 @@ var Point = require('./crypto/point'); | ||
/** | ||
* WARNING: This method is deprecated. Use deriveChild instead. | ||
* | ||
* | ||
* Get a derivated child based on a string or number. | ||
@@ -114,2 +116,31 @@ * | ||
HDPublicKey.prototype.derive = function(arg, hardened) { | ||
return this.deriveChild(arg, hardened); | ||
}; | ||
/** | ||
* WARNING: This method will not be officially supported until v1.0.0. | ||
* | ||
* | ||
* Get a derivated child based on a string or number. | ||
* | ||
* If the first argument is a string, it's parsed as the full path of | ||
* derivation. Valid values for this argument include "m" (which returns the | ||
* same public key), "m/0/1/40/2/1000". | ||
* | ||
* Note that hardened keys can't be derived from a public extended key. | ||
* | ||
* If the first argument is a number, the child with that index will be | ||
* derived. See the example usage for clarification. | ||
* | ||
* @example | ||
* ```javascript | ||
* var parent = new HDPublicKey('xpub...'); | ||
* var child_0_1_2 = parent.deriveChild(0).deriveChild(1).deriveChild(2); | ||
* var copy_of_child_0_1_2 = parent.deriveChild("m/0/1/2"); | ||
* assert(child_0_1_2.xprivkey === copy_of_child_0_1_2); | ||
* ``` | ||
* | ||
* @param {string|number} arg | ||
*/ | ||
HDPublicKey.prototype.deriveChild = function(arg, hardened) { | ||
if (_.isNumber(arg)) { | ||
@@ -131,6 +162,2 @@ return this._deriveWithNumber(arg, hardened); | ||
} | ||
var cached = HDKeyCache.get(this.xpubkey, index, false); | ||
if (cached) { | ||
return cached; | ||
} | ||
@@ -143,3 +170,8 @@ var indexBuffer = BufferUtil.integerAsBuffer(index); | ||
var publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point)); | ||
var publicKey; | ||
try { | ||
publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point)); | ||
} catch (e) { | ||
return this._deriveWithNumber(index + 1); | ||
} | ||
@@ -154,3 +186,3 @@ var derived = new HDPublicKey({ | ||
}); | ||
HDKeyCache.set(this.xpubkey, index, false, derived); | ||
return derived; | ||
@@ -157,0 +189,0 @@ }; |
@@ -134,3 +134,3 @@ 'use strict'; | ||
privatekey: 0xb0, | ||
scripthash: 0x05, | ||
scripthash: 0x32, | ||
xpubkey: 0x019da462, | ||
@@ -145,3 +145,4 @@ xprivkey: 0x019d9cfe, | ||
'dnsseed.koin-project.com', | ||
'dnsseed.weminemnc.com' | ||
'seed-a.litecoin.loshan.co.uk', | ||
'dnsseed.thrasher.io' | ||
] | ||
@@ -161,3 +162,3 @@ }); | ||
privatekey: 0xef, | ||
scripthash: 0xc4, | ||
scripthash: 0x3a, | ||
xpubkey: 0x0436f6e1, | ||
@@ -176,8 +177,7 @@ xprivkey: 0x0436ef7d | ||
var TESTNET = { | ||
PORT: 19333, | ||
NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xfcc1b7dc), | ||
PORT: 19335, | ||
NETWORK_MAGIC: BufferUtil.integerAsBuffer(0xfdd2c8f1), | ||
DNS_SEEDS: [ | ||
'testnet-seed.litecointools.com', | ||
'testnet-seed.ltc.xurious.com', | ||
'testnet-seed.weminemnc.com' | ||
'seed-b.litecoin.loshan.co.uk' | ||
] | ||
@@ -184,0 +184,0 @@ }; |
@@ -339,2 +339,3 @@ 'use strict'; | ||
PrivateKey.prototype.toBuffer = function(){ | ||
// TODO: use `return this.bn.toBuffer({ size: 32 })` in v1.0.0 | ||
return this.bn.toBuffer(); | ||
@@ -344,2 +345,14 @@ }; | ||
/** | ||
* WARNING: This method will not be officially supported until v1.0.0. | ||
* | ||
* | ||
* Will return the private key as a BN buffer without leading zero padding | ||
* | ||
* @returns {Buffer} A buffer of the private key | ||
*/ | ||
PrivateKey.prototype.toBufferNoPadding = function() { | ||
return this.bn.toBuffer(); | ||
}; | ||
/** | ||
* Will return the corresponding public key | ||
@@ -346,0 +359,0 @@ * |
@@ -34,2 +34,76 @@ 'use strict'; | ||
Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, satoshis, flags) { | ||
var scriptPubKey = new Script(); | ||
var stack = []; | ||
if (version === 0) { | ||
if (program.length === 32) { | ||
if (witness.length === 0) { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY'; | ||
return false; | ||
} | ||
var scriptPubKeyBuffer = witness[witness.length - 1]; | ||
scriptPubKey = new Script(scriptPubKeyBuffer); | ||
var hash = Hash.sha256(scriptPubKeyBuffer); | ||
if (hash.toString('hex') !== program.toString('hex')) { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'; | ||
return false; | ||
} | ||
stack = witness.slice(0, -1); | ||
} else if (program.length === 20) { | ||
if (witness.length !== 2) { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'; | ||
return false; | ||
} | ||
scriptPubKey.add(Opcode.OP_DUP); | ||
scriptPubKey.add(Opcode.OP_HASH160); | ||
scriptPubKey.add(program); | ||
scriptPubKey.add(Opcode.OP_EQUALVERIFY); | ||
scriptPubKey.add(Opcode.OP_CHECKSIG); | ||
stack = witness; | ||
} else { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH'; | ||
return false; | ||
} | ||
} else if ((flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)) { | ||
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'; | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
this.initialize(); | ||
this.set({ | ||
script: scriptPubKey, | ||
stack: stack, | ||
sigversion: 1, | ||
satoshis: satoshis | ||
}); | ||
if (!this.evaluate()) { | ||
return false; | ||
} | ||
if (this.stack.length !== 1) { | ||
this.errstr = 'SCRIPT_ERR_EVAL_FALSE'; | ||
return false; | ||
} | ||
var buf = this.stack[this.stack.length - 1]; | ||
if (!Interpreter.castToBool(buf)) { | ||
this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK'; | ||
return false; | ||
} | ||
return true; | ||
}; | ||
/** | ||
@@ -45,6 +119,9 @@ * Verifies a Script by executing it and returns true if it is valid. | ||
* @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants | ||
* @param {number} witness - array of witness data | ||
* @param {number} satoshis - number of satoshis created by this output | ||
* | ||
* Translated from bitcoind's VerifyScript | ||
*/ | ||
Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) { | ||
Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, witness, satoshis) { | ||
var Transaction = require('../transaction'); | ||
@@ -60,2 +137,9 @@ if (_.isUndefined(tx)) { | ||
} | ||
if (_.isUndefined(witness)) { | ||
witness = null; | ||
} | ||
if (_.isUndefined(satoshis)) { | ||
satoshis = 0; | ||
} | ||
this.set({ | ||
@@ -65,2 +149,4 @@ script: scriptSig, | ||
nin: nin, | ||
sigversion: 0, | ||
satoshis: 0, | ||
flags: flags | ||
@@ -110,2 +196,18 @@ }); | ||
var hadWitness = false; | ||
if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { | ||
var witnessValues = {}; | ||
if (scriptPubkey.isWitnessProgram(witnessValues)) { | ||
hadWitness = true; | ||
if (scriptSig.toBuffer().length !== 0) { | ||
return false; | ||
} | ||
if (!this.verifyWitnessProgram(witnessValues.version, witnessValues.program, witness, satoshis, flags)) { | ||
return false; | ||
} | ||
} | ||
} | ||
// Additional validation for spend-to-script-hash transactions: | ||
@@ -152,5 +254,28 @@ if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) { | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { | ||
var p2shWitnessValues = {}; | ||
if (redeemScript.isWitnessProgram(p2shWitnessValues)) { | ||
hadWitness = true; | ||
var redeemScriptPush = new Script(); | ||
redeemScriptPush.add(redeemScript.toBuffer()); | ||
if (scriptSig.toHex() !== redeemScriptPush.toHex()) { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_MALLEATED_P2SH'; | ||
return false; | ||
} | ||
if (!this.verifyWitnessProgram(p2shWitnessValues.version, p2shWitnessValues.program, witness, satoshis, flags)) { | ||
return false; | ||
} | ||
stack = [stack[0]]; | ||
} | ||
} | ||
if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) { | ||
if (!hadWitness && witness.length > 0) { | ||
this.errstr = 'SCRIPT_ERR_WITNESS_UNEXPECTED'; | ||
return false; | ||
} | ||
} | ||
} | ||
@@ -167,2 +292,4 @@ | ||
this.pc = 0; | ||
this.satoshis = 0; | ||
this.sigversion = 0; | ||
this.pbegincodehash = 0; | ||
@@ -183,2 +310,4 @@ this.nOpCount = 0; | ||
this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash; | ||
this.sigversion = typeof obj.sigversion !== 'undefined' ? obj.sigversion : this.sigversion; | ||
this.satoshis = typeof obj.satoshis !== 'undefined' ? obj.satoshis : this.satoshis; | ||
this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount; | ||
@@ -202,2 +331,5 @@ this.vfExec = obj.vfExec || this.vfExec; | ||
// Making v1-v16 witness program non-standard | ||
Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1 << 12); | ||
// Evaluate P2SH subscripts (softfork safe, BIP16). | ||
@@ -243,2 +375,4 @@ Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0); | ||
Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9); | ||
Interpreter.SCRIPT_VERIFY_WITNESS = (1 << 10); | ||
Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 11); | ||
@@ -1124,3 +1258,3 @@ Interpreter.castToBool = function(buf) { | ||
pubkey = PublicKey.fromBuffer(bufPubkey, false); | ||
fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript); | ||
fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.sigversion, this.satoshis); | ||
} catch (e) { | ||
@@ -1214,3 +1348,3 @@ //invalid sig or pubkey | ||
pubkey = PublicKey.fromBuffer(bufPubkey, false); | ||
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript); | ||
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.sigversion, this.satoshis); | ||
} catch (e) { | ||
@@ -1217,0 +1351,0 @@ //invalid sig or pubkey |
@@ -331,3 +331,3 @@ 'use strict'; | ||
Script.prototype.getPublicKey = function() { | ||
$.checkState(this.isPublicKeyOut(), 'Can\'t retreive PublicKey from a non-PK output'); | ||
$.checkState(this.isPublicKeyOut(), 'Can\'t retrieve PublicKey from a non-PK output'); | ||
return this.chunks[0].buf; | ||
@@ -393,2 +393,45 @@ }; | ||
/** | ||
* @returns {boolean} if this is a p2wsh output script | ||
*/ | ||
Script.prototype.isWitnessScriptHashOut = function() { | ||
var buf = this.toBuffer(); | ||
return (buf.length === 34 && buf[0] === 0 && buf[1] === 32); | ||
}; | ||
/** | ||
* @returns {boolean} if this is a p2wpkh output script | ||
*/ | ||
Script.prototype.isWitnessPublicKeyHashOut = function() { | ||
var buf = this.toBuffer(); | ||
return (buf.length === 22 && buf[0] === 0 && buf[1] === 20); | ||
}; | ||
/** | ||
* @param {Object=} values - The return values | ||
* @param {Number} values.version - Set with the witness version | ||
* @param {Buffer} values.program - Set with the witness program | ||
* @returns {boolean} if this is a p2wpkh output script | ||
*/ | ||
Script.prototype.isWitnessProgram = function(values) { | ||
if (!values) { | ||
values = {}; | ||
} | ||
var buf = this.toBuffer(); | ||
if (buf.length < 4 || buf.length > 42) { | ||
return false; | ||
} | ||
if (buf[0] !== Opcode.OP_0 && !(buf[0] >= Opcode.OP_1 && buf[0] <= Opcode.OP_16)) { | ||
return false; | ||
} | ||
if (buf.length === buf[1] + 2) { | ||
values.version = buf[0]; | ||
values.program = buf.slice(2, buf.length); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* @returns {boolean} if this is a p2sh input script | ||
@@ -678,2 +721,11 @@ * Note that these are frequently indistinguishable from pubkeyhashin | ||
Script.prototype.hasCodeseparators = function() { | ||
for (var i = 0; i < this.chunks.length; i++) { | ||
if (this.chunks[i].opcodenum === Opcode.OP_CODESEPARATOR) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
Script.prototype.removeCodeseparators = function() { | ||
@@ -723,2 +775,13 @@ var chunks = []; | ||
Script.buildWitnessMultisigOutFromScript = function(script) { | ||
if (script instanceof Script) { | ||
var s = new Script(); | ||
s.add(Opcode.OP_0); | ||
s.add(Hash.sha256(script.toBuffer())); | ||
return s; | ||
} else { | ||
throw new TypeError('First argument is expected to be a p2sh script'); | ||
} | ||
}; | ||
/** | ||
@@ -725,0 +788,0 @@ * A new Multisig input script for the given public keys, requiring m of those public keys to spend |
@@ -8,1 +8,2 @@ module.exports = require('./transaction'); | ||
module.exports.Sighash = require('./sighash'); | ||
module.exports.SighashWitness = require('./sighashwitness'); |
@@ -61,2 +61,3 @@ 'use strict'; | ||
} | ||
this.witnesses = []; | ||
this.output = params.output ? | ||
@@ -157,2 +158,9 @@ (params.output instanceof Output ? params.output : new Output(params.output)) : undefined; | ||
Input.prototype.getSatoshisBuffer = function() { | ||
$.checkState(this.output instanceof Output); | ||
$.checkState(this.output._satoshisBN); | ||
return new BufferWriter().writeUInt64LEBN(this.output._satoshisBN).toBuffer(); | ||
}; | ||
Input.prototype.isFullySigned = function() { | ||
@@ -174,2 +182,17 @@ throw new errors.AbstractMethodInvoked('Input#isFullySigned'); | ||
Input.prototype.hasWitnesses = function() { | ||
if (this.witnesses && this.witnesses.length > 0) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
Input.prototype.getWitnesses = function() { | ||
return this.witnesses; | ||
}; | ||
Input.prototype.setWitnesses = function(witnesses) { | ||
this.witnesses = witnesses; | ||
}; | ||
Input.prototype.isValidSignature = function(transaction, signature) { | ||
@@ -176,0 +199,0 @@ // FIXME: Refactor signature so this is not necessary |
'use strict'; | ||
/* jshint maxparams:5 */ | ||
var _ = require('lodash'); | ||
@@ -12,3 +14,4 @@ var inherits = require('inherits'); | ||
var Sighash = require('../sighash'); | ||
var PublicKey = require('../../publickey'); | ||
var SighashWitness = require('../sighashwitness'); | ||
var BufferWriter = require('../../encoding/bufferwriter'); | ||
var BufferUtil = require('../../util/buffer'); | ||
@@ -20,3 +23,4 @@ var TransactionSignature = require('../signature'); | ||
*/ | ||
function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { | ||
function MultiSigScriptHashInput(input, pubkeys, threshold, signatures, nestedWitness) { | ||
/* jshint maxstatements:20 */ | ||
Input.apply(this, arguments); | ||
@@ -27,6 +31,17 @@ var self = this; | ||
signatures = signatures || input.signatures; | ||
this.nestedWitness = nestedWitness ? true : false; | ||
this.publicKeys = _.sortBy(pubkeys, function(publicKey) { return publicKey.toString('hex'); }); | ||
this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); | ||
$.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), | ||
if (this.nestedWitness) { | ||
var nested = Script.buildWitnessMultisigOutFromScript(this.redeemScript); | ||
$.checkState(Script.buildScriptHashOut(nested).equals(this.output.script), | ||
'Provided public keys don\'t hash to the provided output (nested witness)'); | ||
var scriptSig = new Script(); | ||
scriptSig.add(nested.toBuffer()); | ||
this.setScript(scriptSig); | ||
} else { | ||
$.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), | ||
'Provided public keys don\'t hash to the provided output'); | ||
} | ||
this.publicKeyIndex = {}; | ||
@@ -68,2 +83,27 @@ _.each(this.publicKeys, function(publicKey, index) { | ||
MultiSigScriptHashInput.prototype.getScriptCode = function() { | ||
var writer = new BufferWriter(); | ||
if (!this.redeemScript.hasCodeseparators()) { | ||
var redeemScriptBuffer = this.redeemScript.toBuffer(); | ||
writer.writeVarintNum(redeemScriptBuffer.length); | ||
writer.write(redeemScriptBuffer); | ||
} else { | ||
throw new Error('@TODO'); | ||
} | ||
return writer.toBuffer(); | ||
}; | ||
MultiSigScriptHashInput.prototype.getSighash = function(transaction, privateKey, index, sigtype) { | ||
var self = this; | ||
var hash; | ||
if (self.nestedWitness) { | ||
var scriptCode = self.getScriptCode(); | ||
var satoshisBuffer = self.getSatoshisBuffer(); | ||
hash = SighashWitness.sighash(transaction, sigtype, index, scriptCode, satoshisBuffer); | ||
} else { | ||
hash = Sighash.sighash(transaction, sigtype, index, self.redeemScript); | ||
} | ||
return hash; | ||
}; | ||
MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) { | ||
@@ -77,2 +117,10 @@ $.checkState(this.output instanceof Output); | ||
if (publicKey.toString() === privateKey.publicKey.toString()) { | ||
var signature; | ||
if (self.nestedWitness) { | ||
var scriptCode = self.getScriptCode(); | ||
var satoshisBuffer = self.getSatoshisBuffer(); | ||
signature = SighashWitness.sign(transaction, privateKey, sigtype, index, scriptCode, satoshisBuffer); | ||
} else { | ||
signature = Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript); | ||
} | ||
results.push(new TransactionSignature({ | ||
@@ -83,3 +131,3 @@ publicKey: privateKey.publicKey, | ||
inputIndex: index, | ||
signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript), | ||
signature: signature, | ||
sigtype: sigtype | ||
@@ -103,8 +151,21 @@ })); | ||
MultiSigScriptHashInput.prototype._updateScript = function() { | ||
this.setScript(Script.buildP2SHMultisigIn( | ||
this.publicKeys, | ||
this.threshold, | ||
this._createSignatures(), | ||
{ cachedMultisig: this.redeemScript } | ||
)); | ||
if (this.nestedWitness) { | ||
var stack = [ | ||
new Buffer(0), | ||
]; | ||
var signatures = this._createSignatures(); | ||
for (var i = 0; i < signatures.length; i++) { | ||
stack.push(signatures[i]); | ||
} | ||
stack.push(this.redeemScript.toBuffer()); | ||
this.setWitnesses(stack); | ||
} else { | ||
var scriptSig = Script.buildP2SHMultisigIn( | ||
this.publicKeys, | ||
this.threshold, | ||
this._createSignatures(), | ||
{ cachedMultisig: this.redeemScript } | ||
); | ||
this.setScript(scriptSig); | ||
} | ||
return this; | ||
@@ -152,5 +213,7 @@ }; | ||
MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) { | ||
// FIXME: Refactor signature so this is not necessary | ||
signature.signature.nhashtype = signature.sigtype; | ||
return Sighash.verify( | ||
if (this.nestedWitness) { | ||
signature.signature.nhashtype = signature.sigtype; | ||
var scriptCode = this.getScriptCode(); | ||
var satoshisBuffer = this.getSatoshisBuffer(); | ||
return SighashWitness.verify( | ||
transaction, | ||
@@ -160,4 +223,16 @@ signature.signature, | ||
signature.inputIndex, | ||
scriptCode, | ||
satoshisBuffer | ||
); | ||
} else { | ||
// FIXME: Refactor signature so this is not necessary | ||
signature.signature.nhashtype = signature.sigtype; | ||
return Sighash.verify( | ||
transaction, | ||
signature.signature, | ||
signature.publicKey, | ||
signature.inputIndex, | ||
this.redeemScript | ||
); | ||
); | ||
} | ||
}; | ||
@@ -164,0 +239,0 @@ |
@@ -16,2 +16,3 @@ 'use strict'; | ||
var Sighash = require('./sighash'); | ||
var SighashWitness = require('./sighashwitness'); | ||
@@ -61,3 +62,2 @@ var Address = require('../address'); | ||
} | ||
var CURRENT_VERSION = 1; | ||
@@ -71,3 +71,3 @@ var DEFAULT_NLOCKTIME = 0; | ||
// Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference | ||
Transaction.FEE_SECURITY_MARGIN = 15; | ||
Transaction.FEE_SECURITY_MARGIN = 150; | ||
@@ -111,2 +111,12 @@ // max amount of satoshis in circulation | ||
}; | ||
var witnessHashProperty = { | ||
configurable: false, | ||
enumerable: true, | ||
get: function() { | ||
return new BufferReader(this._getWitnessHash()).readReverse().toString('hex'); | ||
} | ||
}; | ||
Object.defineProperty(Transaction.prototype, 'witnessHash', witnessHashProperty); | ||
Object.defineProperty(Transaction.prototype, 'hash', hashProperty); | ||
@@ -133,6 +143,14 @@ Object.defineProperty(Transaction.prototype, 'id', hashProperty); | ||
Transaction.prototype._getHash = function() { | ||
return Hash.sha256sha256(this.toBuffer()); | ||
return Hash.sha256sha256(this.toBuffer(true)); | ||
}; | ||
/** | ||
* Retrieve the little endian hash of the transaction including witness data | ||
* @return {Buffer} | ||
*/ | ||
Transaction.prototype._getWitnessHash = function() { | ||
return Hash.sha256sha256(this.toBuffer(false)); | ||
}; | ||
/** | ||
* Retrieve a hexa string that can be used with bitcoind's CLI interface | ||
@@ -173,4 +191,4 @@ * (decoderawtransaction, sendrawtransaction) | ||
if (serializationError) { | ||
serializationError.message += ' Use Transaction#uncheckedSerialize if you want to skip security checks. ' + | ||
'See http://litecore.io/guide/transaction.html#Serialization for more info.'; | ||
serializationError.message += ' - For more information please see: ' + | ||
'http://litecore.io/guide/transaction.html#serialization-checks'; | ||
throw serializationError; | ||
@@ -282,13 +300,31 @@ } | ||
Transaction.prototype.toBuffer = function() { | ||
Transaction.prototype.toBuffer = function(noWitness) { | ||
var writer = new BufferWriter(); | ||
return this.toBufferWriter(writer).toBuffer(); | ||
return this.toBufferWriter(writer, noWitness).toBuffer(); | ||
}; | ||
Transaction.prototype.toBufferWriter = function(writer) { | ||
writer.writeUInt32LE(this.version); | ||
Transaction.prototype.hasWitnesses = function() { | ||
for (var i = 0; i < this.inputs.length; i++) { | ||
if (this.inputs[i].hasWitnesses()) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
Transaction.prototype.toBufferWriter = function(writer, noWitness) { | ||
writer.writeInt32LE(this.version); | ||
var hasWitnesses = this.hasWitnesses(); | ||
if (hasWitnesses && !noWitness) { | ||
writer.write(new Buffer('0001', 'hex')); | ||
} | ||
writer.writeVarintNum(this.inputs.length); | ||
_.each(this.inputs, function(input) { | ||
input.toBufferWriter(writer); | ||
}); | ||
writer.writeVarintNum(this.outputs.length); | ||
@@ -298,2 +334,14 @@ _.each(this.outputs, function(output) { | ||
}); | ||
if (hasWitnesses && !noWitness) { | ||
_.each(this.inputs, function(input) { | ||
var witnesses = input.getWitnesses(); | ||
writer.writeVarintNum(witnesses.length); | ||
for (var j = 0; j < witnesses.length; j++) { | ||
writer.writeVarintNum(witnesses[j].length); | ||
writer.write(witnesses[j]); | ||
} | ||
}); | ||
} | ||
writer.writeUInt32LE(this.nLockTime); | ||
@@ -310,14 +358,37 @@ return writer; | ||
$.checkArgument(!reader.finished(), 'No transaction data received'); | ||
var i, sizeTxIns, sizeTxOuts; | ||
this.version = reader.readUInt32LE(); | ||
sizeTxIns = reader.readVarintNum(); | ||
for (i = 0; i < sizeTxIns; i++) { | ||
this.version = reader.readInt32LE(); | ||
var sizeTxIns = reader.readVarintNum(); | ||
// check for segwit | ||
var hasWitnesses = false; | ||
if (sizeTxIns === 0 && reader.buf[reader.pos] !== 0) { | ||
reader.pos += 1; | ||
hasWitnesses = true; | ||
sizeTxIns = reader.readVarintNum(); | ||
} | ||
for (var i = 0; i < sizeTxIns; i++) { | ||
var input = Input.fromBufferReader(reader); | ||
this.inputs.push(input); | ||
} | ||
sizeTxOuts = reader.readVarintNum(); | ||
for (i = 0; i < sizeTxOuts; i++) { | ||
var sizeTxOuts = reader.readVarintNum(); | ||
for (var j = 0; j < sizeTxOuts; j++) { | ||
this.outputs.push(Output.fromBufferReader(reader)); | ||
} | ||
if (hasWitnesses) { | ||
for (var k = 0; k < sizeTxIns; k++) { | ||
var itemCount = reader.readVarintNum(); | ||
var witnesses = []; | ||
for (var l = 0; l < itemCount; l++) { | ||
var size = reader.readVarintNum(); | ||
var item = reader.read(size); | ||
witnesses.push(item); | ||
} | ||
this.inputs[k].setWitnesses(witnesses); | ||
} | ||
} | ||
this.nLockTime = reader.readUInt32LE(); | ||
@@ -327,2 +398,3 @@ return this; | ||
Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObject() { | ||
@@ -545,4 +617,5 @@ var inputs = []; | ||
* @param {number=} threshold | ||
* @param {boolean=} nestedWitness - Indicates that the utxo is nested witness p2sh | ||
*/ | ||
Transaction.prototype.from = function(utxo, pubkeys, threshold) { | ||
Transaction.prototype.from = function(utxo, pubkeys, threshold, nestedWitness) { | ||
if (_.isArray(utxo)) { | ||
@@ -563,3 +636,3 @@ var self = this; | ||
if (pubkeys && threshold) { | ||
this._fromMultisigUtxo(utxo, pubkeys, threshold); | ||
this._fromMultisigUtxo(utxo, pubkeys, threshold, nestedWitness); | ||
} else { | ||
@@ -592,3 +665,3 @@ this._fromNonP2SH(utxo); | ||
Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) { | ||
Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold, nestedWitness) { | ||
$.checkArgument(threshold <= pubkeys.length, | ||
@@ -613,3 +686,3 @@ 'Number of required signatures must be greater than the number of public keys'); | ||
script: Script.empty() | ||
}, pubkeys, threshold)); | ||
}, pubkeys, threshold, false, nestedWitness)); | ||
}; | ||
@@ -1138,3 +1211,32 @@ | ||
*/ | ||
Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) { | ||
Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript, sigversion, satoshis) { | ||
if (_.isUndefined(sigversion)) { | ||
sigversion = 0; | ||
} | ||
if (sigversion === 1) { | ||
var subscriptBuffer = subscript.toBuffer(); | ||
var scriptCodeWriter = new BufferWriter(); | ||
scriptCodeWriter.writeVarintNum(subscriptBuffer.length); | ||
scriptCodeWriter.write(subscriptBuffer); | ||
var satoshisBuffer; | ||
if (satoshis) { | ||
$.checkState(JSUtil.isNaturalNumber(satoshis)); | ||
satoshisBuffer = new BufferWriter().writeUInt64LEBN(new BN(satoshis)).toBuffer(); | ||
} else { | ||
satoshisBuffer = this.inputs[nin].getSatoshisBuffer(); | ||
} | ||
var verified = SighashWitness.verify( | ||
this, | ||
sig, | ||
pubkey, | ||
nin, | ||
scriptCodeWriter.toBuffer(), | ||
satoshisBuffer | ||
); | ||
return verified; | ||
} | ||
return Sighash.verify(this, sig, pubkey, nin, subscript); | ||
@@ -1141,0 +1243,0 @@ }; |
@@ -21,4 +21,4 @@ 'use strict'; | ||
if (type === 'Buffer') { | ||
var BufferUtil = require('./buffer'); | ||
if (!BufferUtil.isBuffer(argument)) { | ||
var buffer = require('buffer'); // './buffer' fails on cordova & RN | ||
if (!buffer.Buffer.isBuffer(argument)) { | ||
throw new errors.InvalidArgumentType(argument, type, argumentName); | ||
@@ -25,0 +25,0 @@ } |
{ | ||
"name": "litecore-lib", | ||
"version": "0.13.21", | ||
"version": "0.13.22", | ||
"description": "A pure and powerful JavaScript Litecoin library.", | ||
@@ -97,6 +97,6 @@ "author": "BitPay <dev@bitpay.com>", | ||
"devDependencies": { | ||
"litecore-build": "litecoin-project/litecore-build", | ||
"brfs": "^1.2.0", | ||
"chai": "^1.10.0", | ||
"gulp": "^3.8.10", | ||
"gulp": "^3.9.1", | ||
"litecore-build": "litecoin-project/litecore-build", | ||
"sinon": "^1.13.0" | ||
@@ -103,0 +103,0 @@ }, |
@@ -96,3 +96,3 @@ Litecore Library | ||
Copyright 2013-2015 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc. | ||
Copyright 2016 The Litecoin Core Developers | ||
Copyright 2013-2017 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc. | ||
Copyright 2016-2017 The Litecoin Core Developers |
@@ -80,7 +80,7 @@ 'use strict'; | ||
var P2SHLivenet = [ | ||
'342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey', | ||
'33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk', | ||
'37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3', | ||
'3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy', | ||
'\t \n3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy \r' | ||
'MAEpCKqAsN9619X9HnyQnar4AUpP4cDRLk', | ||
'MA92SP8F2rjGoWM4NdVSRt1eJqxGzML8LA', | ||
'MDexQKL1vBbvRX4J7BUReK5vwJspyKC14q', | ||
'MWwgqasit2aZdtrRPLSrQjC8rQEKMrGPit', | ||
'\t \nMWwgqasit2aZdtrRPLSrQjC8rQEKMrGPit \r' | ||
]; | ||
@@ -90,6 +90,6 @@ | ||
var P2SHTestnet = [ | ||
'2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C', | ||
'2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda', | ||
'2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN', | ||
'2NB72XtkjpnATMggui83aEtPawyyKvnbX2o' | ||
'Qacg4vM9pZEwMSPtnfBM2tDKyjnnXXYc77', | ||
'Qhrz7JPBZBcexJxT8hD8tbonVDeYUnGspZ', | ||
'QS39xXsxUoZ8wkFnmRqGgvWnChGYCmqoPJ', | ||
'QeTneucyqtDYVsSxLE5bKaq26NR9uWbqPL' | ||
]; | ||
@@ -124,3 +124,3 @@ | ||
it('getValidationError detects network mismatchs', function() { | ||
var error = Address.getValidationError('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet'); | ||
var error = Address.getValidationError('MDPj1iqqCy23rLccUFvgC8HZq41fB8EH4y', 'testnet'); | ||
should.exist(error); | ||
@@ -130,3 +130,3 @@ }); | ||
it('isValid returns true on a valid address', function() { | ||
var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'livenet'); | ||
var valid = Address.isValid('MDPj1iqqCy23rLccUFvgC8HZq41fB8EH4y', 'livenet'); | ||
valid.should.equal(true); | ||
@@ -136,3 +136,3 @@ }); | ||
it('isValid returns false on network mismatch', function() { | ||
var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet'); | ||
var valid = Address.isValid('MDPj1iqqCy23rLccUFvgC8HZq41fB8EH4y', 'testnet'); | ||
valid.should.equal(false); | ||
@@ -398,5 +398,5 @@ }); | ||
var a = Address.fromScript(s, 'livenet'); | ||
a.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS'); | ||
a.toString().should.equal('MP7nffWprdM6CxdxdCAc4ESzb3XsQQPZMp'); | ||
var b = new Address(s, 'livenet'); | ||
b.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS'); | ||
b.toString().should.equal('MP7nffWprdM6CxdxdCAc4ESzb3XsQQPZMp'); | ||
}); | ||
@@ -410,3 +410,3 @@ | ||
it('returns the same address if the script is a pay to script hash out', function() { | ||
var address = '3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'; | ||
var address = 'MHkuYq6Sz31ofGwL5eqMau2grNwBCLJo11'; | ||
var script = Script.buildScriptHashOut(new Address(address)); | ||
@@ -545,5 +545,5 @@ Address(script, Networks.livenet).toString().should.equal(address); | ||
var address = Address.createMultisig(publics, 2, Networks.livenet); | ||
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y'); | ||
address.toString().should.equal('MN6yhK8peWnHTd3PaKkKWcoUocPcWD9Cmx'); | ||
address = new Address(publics, 2, Networks.livenet); | ||
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y'); | ||
address.toString().should.equal('MN6yhK8peWnHTd3PaKkKWcoUocPcWD9Cmx'); | ||
}); | ||
@@ -553,5 +553,10 @@ | ||
var address = Address.createMultisig(publics, 2, Networks.testnet); | ||
address.toString().should.equal('2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf'); | ||
address.toString().should.equal('QaooaBX8KxVJ16A5mgQsPcymqeTAFqTmhh'); | ||
}); | ||
it('can create an address from a set of public keys with a nested witness program', function() { | ||
var address = Address.createMultisig(publics, 2, Networks.livenet, true); | ||
address.toString().should.equal('3PpK1bBqUmPK3Q6QPSUK7BQSZ1DMWL6aes'); | ||
}); | ||
it('can also be created by Address.createMultisig', function() { | ||
@@ -558,0 +563,0 @@ var address = Address.createMultisig(publics, 2); |
@@ -82,2 +82,12 @@ 'use strict'; | ||
describe('version', function() { | ||
it('is interpreted as an int32le', function() { | ||
var hex = 'ffffffff00000000000000000000000000000000000000000000000000000000000000004141414141414141414141414141414141414141414141414141414141414141010000000200000003000000'; | ||
var header = BlockHeader.fromBuffer(new Buffer(hex, 'hex')); | ||
header.version.should.equal(-1); | ||
header.timestamp.should.equal(1); | ||
}); | ||
}); | ||
describe('#fromObject', function() { | ||
@@ -84,0 +94,0 @@ |
@@ -12,3 +12,3 @@ [ | ||
[ | ||
"3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", | ||
"MJZWZqmykQ32rvH8vUnW9jEPbyGg7agWQZ", | ||
"74f209f6ea907e2ea48f74fae05782ae8a665257", | ||
@@ -31,3 +31,3 @@ { | ||
[ | ||
"2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", | ||
"QVeyDxTK7GiQD5RoyCRxiCDEh8UT4iUJnt", | ||
"6349a418fc4578d10a372b54b45c280cc8c4382f", | ||
@@ -86,3 +86,3 @@ { | ||
[ | ||
"3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", | ||
"MWwgqasit2aZdtrRPLSrQjC8rQEKMrGPit", | ||
"fcc5460dd6e2487c7d75b1963625da0e8f4c5975", | ||
@@ -105,3 +105,3 @@ { | ||
[ | ||
"2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", | ||
"Qec8RUd8PgAMi6dKDKdHQ7zu71kyQNeU5m", | ||
"c579342c2c4c9220205e2cdc285617040c924a0a", | ||
@@ -160,3 +160,3 @@ { | ||
[ | ||
"3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", | ||
"MGzXGU1WDvKPMDj8fpEacJ6t8LqyMCyzrK", | ||
"63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", | ||
@@ -179,3 +179,3 @@ { | ||
[ | ||
"2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", | ||
"QeTneucyqtDYVsSxLE5bKaq26NR9uWbqPL", | ||
"c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", | ||
@@ -234,3 +234,3 @@ { | ||
[ | ||
"33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", | ||
"MA92SP8F2rjGoWM4NdVSRt1eJqxGzML8LA", | ||
"188f91a931947eddd7432d6e614387e32b244709", | ||
@@ -253,3 +253,3 @@ { | ||
[ | ||
"2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", | ||
"QS39xXsxUoZ8wkFnmRqGgvWnChGYCmqoPJ", | ||
"3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", | ||
@@ -308,3 +308,3 @@ { | ||
[ | ||
"3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", | ||
"MWR9EYk2WYnC6kzQc4VHnJsygt3aHCxaxg", | ||
"f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", | ||
@@ -327,3 +327,3 @@ { | ||
[ | ||
"2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", | ||
"Qhrz7JPBZBcexJxT8hD8tbonVDeYUnGspZ", | ||
"e930e1834a4d234702773951d627cce82fbb5d2e", | ||
@@ -382,3 +382,3 @@ { | ||
[ | ||
"37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", | ||
"MDexQKL1vBbvRX4J7BUReK5vwJspyKC14q", | ||
"3f210e7277c899c3a155cc1c90f4106cbddeec6e", | ||
@@ -401,3 +401,3 @@ { | ||
[ | ||
"2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", | ||
"Qacg4vM9pZEwMSPtnfBM2tDKyjnnXXYc77", | ||
"99b31df7c9068d1481b596578ddbb4d3bd90baeb", | ||
@@ -456,3 +456,3 @@ { | ||
[ | ||
"3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", | ||
"MGYSb2x728Ld57mTe3d9yga22VybNQZo9V", | ||
"5ece0cadddc415b1980f001785947120acdb36fc", | ||
@@ -459,0 +459,0 @@ { |
@@ -27,5 +27,2 @@ [ | ||
["Tests for CheckTransaction()"], | ||
["No inputs"], | ||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], | ||
"0100000000010000000000000000015100000000", "P2SH"], | ||
@@ -32,0 +29,0 @@ ["No outputs"], |
@@ -67,5 +67,5 @@ [ | ||
"from", [{ | ||
"address":"38nw4sTs3fCH1YiBjYeQAX1t9eWMxpek8Z","txid":"073281b2cc94e879aaf30ea2e92947d9827b270015849d3a5b96a89ee15bfa66","vout":0,"ts":1418877950,"scriptPubKey":"a9144de752833233fe69a20064f29b2ca0f6399c8af387","amount":0.00408512,"confirmationsFromCache":false | ||
"address":"MF15Nkspzn3hp3z5qRdjzAGHUM6oxq6LQD","txid":"073281b2cc94e879aaf30ea2e92947d9827b270015849d3a5b96a89ee15bfa66","vout":0,"ts":1418877950,"scriptPubKey":"a9144de752833233fe69a20064f29b2ca0f6399c8af387","amount":0.00408512,"confirmationsFromCache":false | ||
}, ["03411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba", "03bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab", "03c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea7330"], 2], | ||
"to", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9", 300299], | ||
"to", ["MHo8mjLisM33KFPCAkb2FSCtFoTBUvSr3f", 300299], | ||
"sign", [["T9oGpupr8xxEwtZxv24hsjVmYm38ULAzWpzwarp1tYD7xWtGUbGL", "T9QLZR1Z9DeCJ2GRUZDQbkYff5ANA8npyErW8GB3KVioKhBw2119"]], | ||
@@ -75,9 +75,9 @@ "serialize", "010000000166fa5be19ea8965b3a9d841500277b82d94729e9a20ef3aa79e894ccb281320700000000fc0047304402202f66fcfc0d5bff109ec12327ca37e0bc7722d08da9538f12468994799534bed602203a0b374f3a6810b0ee26028c390e14f5b6bada8fa390f4364d70d04aee240d350147304402206757f710f25937cd846fd8c56687c463a4561e9e0421fc173c78eaf2de9b9a7d02204995db6b81513b67a42b09dabab6ed4cb90901c52f6f945b768827a9390bda60014c69522103411e021210a933c247ea9c8dad4bbead281597d508ad84e899de13e4ce98b4ba2103bda2c3cc11a391b36e3d695b03ab42b96fe04086b2349056108d858983e60dab2103c16e6ecf4e02bf9db23d3247ab92db8881f0866133ffb530c3470f6d8dea733053aeffffffff010b9504000000000017a9146c8d8b04c6a1e664b1ec20ec932760760c97688e8700000000" | ||
[ | ||
"from", [{"address":"3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9","txid":"afbf98ca4a43db8915d75184b5204fbe71d916482adfe85cb0ed3635764fc220","vout":0,"ts":1418878108,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00408512,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2 | ||
"from", [{"address":"MHo8mjLisM33KFPCAkb2FSCtFoTBUvSr3f","txid":"afbf98ca4a43db8915d75184b5204fbe71d916482adfe85cb0ed3635764fc220","vout":0,"ts":1418878108,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00408512,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2 | ||
], | ||
"from", [ | ||
{"address":"3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9","txid":"dc2e197ab72f71912c39bc23a42d823a3aa8d469fe65eb591c086e60d14c64a0","vout":0,"ts":1418878014,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00300299,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2], | ||
"to", ["38nw4sTs3fCH1YiBjYeQAX1t9eWMxpek8Z", 150000], | ||
"to", ["38nw4sTs3fCH1YiBjYeQAX1t9eWMxpek8Z", 160000], | ||
"change", ["3BazTqvkvEBcWk7J4sbgRnxUw6rjYrogf9"], | ||
{"address":"MHo8mjLisM33KFPCAkb2FSCtFoTBUvSr3f","txid":"dc2e197ab72f71912c39bc23a42d823a3aa8d469fe65eb591c086e60d14c64a0","vout":0,"ts":1418878014,"scriptPubKey":"a9146c8d8b04c6a1e664b1ec20ec932760760c97688e87","amount":0.00300299,"confirmationsFromCache":false}, ["020483ebb834d91d494a3b649cf0e8f5c9c4fcec5f194ab94341cc99bb440007f2", "0271ebaeef1c2bf0c1a4772d1391eab03e4d96a6e9b48551ab4e4b0d2983eb452b", "03a659828aabe443e2dedabb1db5a22335c5ace5b5b7126998a288d63c99516dd8"], 2], | ||
"to", ["MF15Nkspzn3hp3z5qRdjzAGHUM6oxq6LQD", 150000], | ||
"to", ["MF15Nkspzn3hp3z5qRdjzAGHUM6oxq6LQD", 160000], | ||
"change", ["MHo8mjLisM33KFPCAkb2FSCtFoTBUvSr3f"], | ||
"sign", ["T8JRCpf9Szca8vUPZ2DvPU5Fq7rsKbxsixXmzVMgVqUDBeJvCibG"], | ||
@@ -84,0 +84,0 @@ "sign", ["TAZWwMWmEwBMXd1ws3TbQYE6H7be2WyskaAimRPbJADyW5T7wD6P"], |
@@ -16,2 +16,3 @@ 'use strict'; | ||
var expect = require('chai').expect; | ||
var sinon = require('sinon'); | ||
var bitcore = require('..'); | ||
@@ -225,2 +226,107 @@ var Networks = bitcore.Networks; | ||
it('should use full 32 bytes for private key data that is hashed (as per bip32)', function() { | ||
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki | ||
var privateKeyBuffer = new Buffer('00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd', 'hex'); | ||
var chainCodeBuffer = new Buffer('9c8a5c863e5941f3d99453e6ba66b328bb17cf0b8dec89ed4fc5ace397a1c089', 'hex'); | ||
var key = HDPrivateKey.fromObject({ | ||
network: 'testnet', | ||
depth: 0, | ||
parentFingerPrint: 0, | ||
childIndex: 0, | ||
privateKey: privateKeyBuffer, | ||
chainCode: chainCodeBuffer | ||
}); | ||
var derived = key.deriveChild("m/44'/0'/0'/0/0'"); | ||
derived.privateKey.toString().should.equal('3348069561d2a0fb925e74bf198762acc47dce7db27372257d2d959a9e6f8aeb'); | ||
}); | ||
it('should NOT use full 32 bytes for private key data that is hashed with nonCompliant flag', function() { | ||
// This is to test that the previously implemented non-compliant to BIP32 | ||
var privateKeyBuffer = new Buffer('00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd', 'hex'); | ||
var chainCodeBuffer = new Buffer('9c8a5c863e5941f3d99453e6ba66b328bb17cf0b8dec89ed4fc5ace397a1c089', 'hex'); | ||
var key = HDPrivateKey.fromObject({ | ||
network: 'testnet', | ||
depth: 0, | ||
parentFingerPrint: 0, | ||
childIndex: 0, | ||
privateKey: privateKeyBuffer, | ||
chainCode: chainCodeBuffer | ||
}); | ||
var derived = key.deriveNonCompliantChild("m/44'/0'/0'/0/0'"); | ||
derived.privateKey.toString().should.equal('4811a079bab267bfdca855b3bddff20231ff7044e648514fa099158472df2836'); | ||
}); | ||
it('should NOT use full 32 bytes for private key data that is hashed with the nonCompliant derive method', function() { | ||
// This is to test that the previously implemented non-compliant to BIP32 | ||
var privateKeyBuffer = new Buffer('00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd', 'hex'); | ||
var chainCodeBuffer = new Buffer('9c8a5c863e5941f3d99453e6ba66b328bb17cf0b8dec89ed4fc5ace397a1c089', 'hex'); | ||
var key = HDPrivateKey.fromObject({ | ||
network: 'testnet', | ||
depth: 0, | ||
parentFingerPrint: 0, | ||
childIndex: 0, | ||
privateKey: privateKeyBuffer, | ||
chainCode: chainCodeBuffer | ||
}); | ||
var derived = key.derive("m/44'/0'/0'/0/0'"); | ||
derived.privateKey.toString().should.equal('4811a079bab267bfdca855b3bddff20231ff7044e648514fa099158472df2836'); | ||
}); | ||
describe('edge cases', function() { | ||
var sandbox = sinon.sandbox.create(); | ||
afterEach(function() { | ||
sandbox.restore(); | ||
}); | ||
it('will handle edge case that derived private key is invalid', function() { | ||
var invalid = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); | ||
var privateKeyBuffer = new Buffer('5f72914c48581fc7ddeb944a9616389200a9560177d24f458258e5b04527bcd1', 'hex'); | ||
var chainCodeBuffer = new Buffer('39816057bba9d952fe87fe998b7fd4d690a1bb58c2ff69141469e4d1dffb4b91', 'hex'); | ||
var unstubbed = bitcore.crypto.BN.prototype.toBuffer; | ||
var count = 0; | ||
var stub = sandbox.stub(bitcore.crypto.BN.prototype, 'toBuffer', function(args) { | ||
// On the fourth call to the function give back an invalid private key | ||
// otherwise use the normal behavior. | ||
count++; | ||
if (count === 4) { | ||
return invalid; | ||
} | ||
var ret = unstubbed.apply(this, arguments); | ||
return ret; | ||
}); | ||
sandbox.spy(bitcore.PrivateKey, 'isValid'); | ||
var key = HDPrivateKey.fromObject({ | ||
network: 'testnet', | ||
depth: 0, | ||
parentFingerPrint: 0, | ||
childIndex: 0, | ||
privateKey: privateKeyBuffer, | ||
chainCode: chainCodeBuffer | ||
}); | ||
var derived = key.derive("m/44'"); | ||
derived.privateKey.toString().should.equal('b15bce3608d607ee3a49069197732c656bca942ee59f3e29b4d56914c1de6825'); | ||
bitcore.PrivateKey.isValid.callCount.should.equal(2); | ||
}); | ||
it('will handle edge case that a derive public key is invalid', function() { | ||
var publicKeyBuffer = new Buffer('029e58b241790284ef56502667b15157b3fc58c567f044ddc35653860f9455d099', 'hex'); | ||
var chainCodeBuffer = new Buffer('39816057bba9d952fe87fe998b7fd4d690a1bb58c2ff69141469e4d1dffb4b91', 'hex'); | ||
var key = new HDPublicKey({ | ||
network: 'testnet', | ||
depth: 0, | ||
parentFingerPrint: 0, | ||
childIndex: 0, | ||
chainCode: chainCodeBuffer, | ||
publicKey: publicKeyBuffer | ||
}); | ||
var unstubbed = bitcore.PublicKey.fromPoint; | ||
bitcore.PublicKey.fromPoint = function() { | ||
bitcore.PublicKey.fromPoint = unstubbed; | ||
throw new Error('Point cannot be equal to Infinity'); | ||
}; | ||
sandbox.spy(key, '_deriveWithNumber'); | ||
var derived = key.derive("m/44"); | ||
key._deriveWithNumber.callCount.should.equal(2); | ||
key.publicKey.toString().should.equal('029e58b241790284ef56502667b15157b3fc58c567f044ddc35653860f9455d099'); | ||
}); | ||
}); | ||
describe('seed', function() { | ||
@@ -227,0 +333,0 @@ |
@@ -274,10 +274,3 @@ 'use strict'; | ||
}); | ||
it('should use the cache', function() { | ||
var pubkey = new HDPublicKey(xpubkey); | ||
var derived1 = pubkey.derive(0); | ||
var derived2 = pubkey.derive(0); | ||
derived1.should.equal(derived2); | ||
}); | ||
}); | ||
}); |
@@ -26,8 +26,7 @@ 'use strict'; | ||
networks.disableRegtest(); | ||
networks.testnet.networkMagic.should.deep.equal(new Buffer('fcc1b7dc', 'hex')); | ||
networks.testnet.port.should.equal(19333); | ||
networks.testnet.networkMagic.should.deep.equal(new Buffer('fdd2c8f1', 'hex')); | ||
networks.testnet.port.should.equal(19335); | ||
networks.testnet.dnsSeeds.should.deep.equal([ | ||
'testnet-seed.litecointools.com', | ||
'testnet-seed.ltc.xurious.com', | ||
'testnet-seed.weminemnc.com' | ||
'seed-b.litecoin.loshan.co.uk' | ||
]); | ||
@@ -34,0 +33,0 @@ }); |
@@ -333,2 +333,25 @@ 'use strict'; | ||
}); | ||
it('will output a 31 byte buffer', function() { | ||
var bn = BN.fromBuffer(new Buffer('9b5a0e8fee1835e21170ce1431f9b6f19b487e67748ed70d8a4462bc031915', 'hex')); | ||
var privkey = new PrivateKey(bn); | ||
var buffer = privkey.toBufferNoPadding(); | ||
buffer.length.should.equal(31); | ||
}); | ||
// TODO: enable for v1.0.0 when toBuffer is changed to always be 32 bytes long | ||
// it('will output a 32 byte buffer', function() { | ||
// var bn = BN.fromBuffer(new Buffer('9b5a0e8fee1835e21170ce1431f9b6f19b487e67748ed70d8a4462bc031915', 'hex')); | ||
// var privkey = new PrivateKey(bn); | ||
// var buffer = privkey.toBuffer(); | ||
// buffer.length.should.equal(32); | ||
// }); | ||
// TODO: enable for v1.0.0 when toBuffer is changed to always be 32 bytes long | ||
// it('should return buffer with length equal 32', function() { | ||
// var bn = BN.fromBuffer(buf.slice(0, 31)); | ||
// var privkey = new PrivateKey(bn, 'livenet'); | ||
// var expected = Buffer.concat([ new Buffer([0]), buf.slice(0, 31) ]); | ||
// privkey.toBuffer().toString('hex').should.equal(expected.toString('hex')); | ||
// }); | ||
}); | ||
@@ -335,0 +358,0 @@ |
'use strict'; | ||
var should = require('chai').should(); | ||
var sinon = require('sinon'); | ||
var bitcore = require('../..'); | ||
@@ -100,2 +101,107 @@ var Interpreter = bitcore.Script.Interpreter; | ||
describe('#verifyWitnessProgram', function() { | ||
it('will return true if witness program greater than 0', function() { | ||
var si = Interpreter(); | ||
var version = 1; | ||
var program = new Buffer('bcbd1db07ce89d1f4050645c26c90ce78b67eff78460002a4d5c10410958e064', 'hex'); | ||
var witness = [new Buffer('bda0eeeb166c8bfeaee88dedc8efa82d3bea35aac5be253902f59d52908bfe25', 'hex')]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(true); | ||
}); | ||
it('will return false with error if witness length is 0', function() { | ||
var si = Interpreter(); | ||
var version = 0; | ||
var program = new Buffer('bcbd1db07ce89d1f4050645c26c90ce78b67eff78460002a4d5c10410958e064', 'hex'); | ||
var witness = []; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY'); | ||
}); | ||
it('will return false if program hash mismatch (version 0, 32 byte program)', function() { | ||
var si = Interpreter(); | ||
var version = 0; | ||
var program = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'); | ||
}); | ||
it('will return false if witness stack doesn\'t have two items (version 0, 20 byte program)', function() { | ||
var si = Interpreter(); | ||
var version = 0; | ||
var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH'); | ||
}); | ||
it('will return false if program wrong length for version 0', function() { | ||
var si = Interpreter(); | ||
var version = 0; | ||
var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH'); | ||
}); | ||
it('will return false with discourage upgradable witness program', function() { | ||
var si = Interpreter(); | ||
var version = 1; | ||
var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM'); | ||
}); | ||
it('will return false with error if stack doesn\'t have exactly one item', function() { | ||
var si = Interpreter(); | ||
si.evaluate = sinon.stub().returns(true); | ||
var version = 0; | ||
var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_EVAL_FALSE'); | ||
}); | ||
it('will return false if last item in stack casts to false', function() { | ||
var si = Interpreter(); | ||
si.evaluate = function() { | ||
si.stack = [new Buffer('00', 'hex')]; | ||
return true; | ||
}; | ||
var version = 0; | ||
var program = new Buffer('b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6', 'hex'); | ||
var witness = [ | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), | ||
new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') | ||
]; | ||
var satoshis = 1; | ||
var flags = 0; | ||
si.verifyWitnessProgram(version, program, witness, satoshis, flags).should.equal(false); | ||
si.errstr.should.equal('SCRIPT_ERR_EVAL_FALSE_IN_STACK'); | ||
}); | ||
}); | ||
describe('#verify', function() { | ||
@@ -102,0 +208,0 @@ |
@@ -405,2 +405,56 @@ 'use strict'; | ||
describe('#isWitnessScriptHashOut', function() { | ||
it('should recognize this script as p2wsh', function() { | ||
Script('OP_0 32 0xa99d08fbec6958f4d4a3776c3728ec448934d25fe1142054b8b68bac866dfc3a') | ||
.isWitnessScriptHashOut().should.equal(true); | ||
Script('0020a99d08fbec6958f4d4a3776c3728ec448934d25fe1142054b8b68bac866dfc3a') | ||
.isWitnessScriptHashOut().should.equal(true); | ||
}); | ||
it('should NOT identify as p2wsh', function() { | ||
Script('OP_0 20 0x799d283e7f92af1dd242bf4eea513c6efd117de2') | ||
.isWitnessScriptHashOut().should.equal(false); | ||
}); | ||
}); | ||
describe('#isWitnessPublicKeyHashOut', function() { | ||
it('should identify as p2wpkh', function() { | ||
Script('OP_0 20 0x799d283e7f92af1dd242bf4eea513c6efd117de2') | ||
.isWitnessPublicKeyHashOut().should.equal(true); | ||
Script('0014799d283e7f92af1dd242bf4eea513c6efd117de2').isWitnessPublicKeyHashOut().should.equal(true); | ||
}); | ||
it('should NOT identify as p2wpkh', function() { | ||
Script('OP_0 32 0xa99d08fbec6958f4d4a3776c3728ec448934d25fe1142054b8b68bac866dfc3a') | ||
.isWitnessPublicKeyHashOut().should.equal(false); | ||
}); | ||
}); | ||
describe('#isWitnessProgram', function() { | ||
it('will default values to empty object', function() { | ||
Script('OP_0 20 0x799d283e7f92af1dd242bf4eea513c6efd117de2') | ||
.isWitnessProgram().should.equal(true); | ||
}); | ||
it('will return false if script is data push longer than 40 bytes', function() { | ||
Script('OP_0 42 0xd06863c385592423903682926825c495b6cf88fd7cd6159ffd72f778ca475d3046e7b87835d3b457cd') | ||
.isWitnessProgram().should.equal(false); | ||
}); | ||
it('will return false if first byte op_code is greater than OP_16', function() { | ||
Script('OP_NOP 20 0x799d283e7f92af1dd242bf4eea513c6efd117de2') | ||
.isWitnessProgram().should.equal(false); | ||
}); | ||
it('will return true with datapush of 20', function() { | ||
var values = {}; | ||
Script('OP_0 20 0x799d283e7f92af1dd242bf4eea513c6efd117de2') | ||
.isWitnessProgram(values).should.equal(true); | ||
values.version.should.equal(0); | ||
values.program.toString('hex').should.equal('799d283e7f92af1dd242bf4eea513c6efd117de2'); | ||
}); | ||
it('will return true with datapush of 32', function() { | ||
var values = {}; | ||
Script('OP_0 32 0xc756f6d660d4aaad55534cac599a0d9bf5c7e8f70363d22926291811a168c620') | ||
.isWitnessProgram(values).should.equal(true); | ||
values.version.should.equal(0); | ||
values.program.toString('hex').should.equal('c756f6d660d4aaad55534cac599a0d9bf5c7e8f70363d22926291811a168c620'); | ||
}); | ||
}); | ||
describe('#isPushOnly', function() { | ||
@@ -661,2 +715,14 @@ it('should know these scripts are or aren\'t push only', function() { | ||
}); | ||
describe('#buildWitnessMultisigOutFromScript', function() { | ||
it('it will build nested witness scriptSig', function() { | ||
var redeemScript = bitcore.Script(); | ||
var redeemHash = bitcore.crypto.Hash.sha256(redeemScript.toBuffer()); | ||
var s = Script.buildWitnessMultisigOutFromScript(redeemScript); | ||
var buf = s.toBuffer(); | ||
buf[0].should.equal(0); | ||
buf.slice(2, 34).toString('hex').should.equal(redeemHash.toString('hex')); | ||
}); | ||
}); | ||
describe('#buildPublicKeyHashOut', function() { | ||
@@ -751,3 +817,3 @@ it('should create script from livenet address', function() { | ||
it('inherits network property form an address', function() { | ||
var address = new Address('34Nn91aTGaULqWsZiunrBPHzFBDrZ3B8XS'); | ||
var address = new Address('MAavStzRDhKme29TpnnC12YPZspJYiPgsu'); | ||
var script = Script.buildScriptHashOut(address); | ||
@@ -832,3 +898,3 @@ should.exist(script._network); | ||
it('for a P2SH address', function() { | ||
var address = Address.fromString('3GhtMmAbWrUf6Y8vDxn9ETB14R6V7Br3mt'); | ||
var address = Address.fromString('MNv2feaZTyL5u3QpKqmV46RQP7gw8bg6N4'); | ||
var script = new Script(address); | ||
@@ -875,3 +941,3 @@ expect(BufferUtil.equal(script.getData(), address.hashBuffer)).to.be.true(); | ||
it('for a P2SH address', function() { | ||
var stringAddress = '3GhtMmAbWrUf6Y8vDxn9ETB14R6V7Br3mt'; | ||
var stringAddress = 'MNv2feaZTyL5u3QpKqmV46RQP7gw8bg6N4'; | ||
var address = new Address(stringAddress); | ||
@@ -903,3 +969,3 @@ var script = new Script(address); | ||
var script = new Script('OP_HASH160 20 0x99d29051af0c29adcb9040034752bba7dde33e35 OP_EQUAL'); | ||
script.toAddress().toString().should.equal('3FiMZ7stbfH2WG5JQ7CiuzrFo7CEnGUcAP'); | ||
script.toAddress().toString().should.equal('MMvVs1HrYn8TJmMCVzC4je6f7ongktNnds'); | ||
}); | ||
@@ -909,3 +975,3 @@ it('works for p2sh input', function() { | ||
var script = new Script('OP_FALSE 72 0x3045022100e824fbe979fac5834d0062dd5a4e82a898e00ac454bd254cd708ad28530816f202206251ff0fa4dd70c0524c690d4e4deb2bd167297e7bbdf6743b4a8050d681555001 37 0x512102ff3ae0aaa4679ea156d5581dbe6695cc0c311df0aa42af76670d0debbd8f672951ae'); | ||
script.toAddress().toString().should.equal('3GYicPxCvsKvbJmZNBBeWkC3cLuGFhtrQi'); | ||
script.toAddress().toString().should.equal('MNkrvHNAszBMPp3TU4AzLPSSw3ViHHZLZe'); | ||
}); | ||
@@ -912,0 +978,0 @@ |
@@ -21,3 +21,3 @@ 'use strict'; | ||
var output = { | ||
address: '33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb', | ||
address: 'MACk3uzQWfUoPw9FVGsSZLDVeXcCKarBfA', | ||
prevTxId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', | ||
@@ -24,0 +24,0 @@ outputIndex: 0, |
@@ -24,3 +24,3 @@ 'use strict'; | ||
var public3 = privateKey3.publicKey; | ||
var address = new Address('33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb'); | ||
var address = new Address('MACk3uzQWfUoPw9FVGsSZLDVeXcCKarBfA'); | ||
@@ -27,0 +27,0 @@ var output = { |
@@ -24,6 +24,6 @@ 'use strict'; | ||
var public3 = privateKey3.publicKey; | ||
var address = new Address('33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb'); | ||
var address = new Address('MACk3uzQWfUoPw9FVGsSZLDVeXcCKarBfA'); | ||
var output = { | ||
address: '33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb', | ||
address: 'MACk3uzQWfUoPw9FVGsSZLDVeXcCKarBfA', | ||
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', | ||
@@ -115,2 +115,35 @@ outputIndex: 0, | ||
}); | ||
it('will get the scriptCode for nested witness', function() { | ||
var address = Address.createMultisig([public1, public2, public3], 2, 'testnet', true); | ||
var utxo = { | ||
address: address.toString(), | ||
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', | ||
outputIndex: 0, | ||
script: new Script(address), | ||
satoshis: 1000000 | ||
}; | ||
var transaction = new Transaction() | ||
.from(utxo, [public1, public2, public3], 2, true) | ||
.to(address, 1000000); | ||
var input = transaction.inputs[0]; | ||
var scriptCode = input.getScriptCode(); | ||
scriptCode.toString('hex').should.equal('695221025c95ec627038e85b5688a9b3d84d28c5ebe66e8c8d697d498e20fe96e3b1ab1d2102cdddfc974d41a62f1f80081deee70592feb7d6e6cf6739d6592edbe7946720e72103c95924e02c240b5545089c69c6432447412b58be43fd671918bd184a5009834353ae'); | ||
}); | ||
it('will get the satoshis buffer for nested witness', function() { | ||
var address = Address.createMultisig([public1, public2, public3], 2, 'testnet', true); | ||
var utxo = { | ||
address: address.toString(), | ||
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', | ||
outputIndex: 0, | ||
script: new Script(address), | ||
satoshis: 1000000 | ||
}; | ||
var transaction = new Transaction() | ||
.from(utxo, [public1, public2, public3], 2, true) | ||
.to(address, 1000000); | ||
var input = transaction.inputs[0]; | ||
var satoshisBuffer = input.getSatoshisBuffer(); | ||
satoshisBuffer.toString('hex').should.equal('40420f0000000000'); | ||
}); | ||
}); |
@@ -23,3 +23,3 @@ 'use strict'; | ||
var output = { | ||
address: '33zbk2aSZYdNbRsMPPt6jgy6Kq1kQreqeb', | ||
address: 'MACk3uzQWfUoPw9FVGsSZLDVeXcCKarBfA', | ||
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140', | ||
@@ -26,0 +26,0 @@ outputIndex: 0, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
3679127
143
74860
2