smartledger-bsv 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +36 -0
- package/README.md +305 -0
- package/SECURITY.md +75 -0
- package/bsv-ecies.min.js +12 -0
- package/bsv-message.min.js +10 -0
- package/bsv-mnemonic.min.js +12 -0
- package/bsv.d.ts +440 -0
- package/bsv.min.js +37 -0
- package/ecies/index.js +1 -0
- package/index.js +101 -0
- package/lib/address.js +526 -0
- package/lib/block/block.js +277 -0
- package/lib/block/blockheader.js +294 -0
- package/lib/block/index.js +4 -0
- package/lib/block/merkleblock.js +316 -0
- package/lib/crypto/bn.js +278 -0
- package/lib/crypto/ecdsa.js +330 -0
- package/lib/crypto/elliptic-fixed.js +74 -0
- package/lib/crypto/hash.browser.js +171 -0
- package/lib/crypto/hash.js +2 -0
- package/lib/crypto/hash.node.js +171 -0
- package/lib/crypto/point.js +217 -0
- package/lib/crypto/random.js +37 -0
- package/lib/crypto/signature.js +410 -0
- package/lib/crypto/smartledger_verify.js +109 -0
- package/lib/ecies/bitcore-ecies.js +163 -0
- package/lib/ecies/electrum-ecies.js +175 -0
- package/lib/ecies/errors.js +16 -0
- package/lib/ecies/index.js +1 -0
- package/lib/encoding/base58.js +108 -0
- package/lib/encoding/base58check.js +112 -0
- package/lib/encoding/bufferreader.js +200 -0
- package/lib/encoding/bufferwriter.js +150 -0
- package/lib/encoding/varint.js +71 -0
- package/lib/errors/index.js +57 -0
- package/lib/errors/spec.js +184 -0
- package/lib/hdprivatekey.js +655 -0
- package/lib/hdpublickey.js +509 -0
- package/lib/message/index.js +4 -0
- package/lib/message/message.js +181 -0
- package/lib/mnemonic/errors.js +18 -0
- package/lib/mnemonic/index.js +4 -0
- package/lib/mnemonic/mnemonic.js +304 -0
- package/lib/mnemonic/pbkdf2.js +68 -0
- package/lib/mnemonic/words/chinese.js +5 -0
- package/lib/mnemonic/words/english.js +5 -0
- package/lib/mnemonic/words/french.js +5 -0
- package/lib/mnemonic/words/index.js +8 -0
- package/lib/mnemonic/words/italian.js +5 -0
- package/lib/mnemonic/words/japanese.js +5 -0
- package/lib/mnemonic/words/spanish.js +5 -0
- package/lib/networks.js +392 -0
- package/lib/opcode.js +248 -0
- package/lib/privatekey.js +373 -0
- package/lib/publickey.js +387 -0
- package/lib/script/index.js +3 -0
- package/lib/script/interpreter.js +1807 -0
- package/lib/script/script.js +1153 -0
- package/lib/transaction/index.js +7 -0
- package/lib/transaction/input/index.js +6 -0
- package/lib/transaction/input/input.js +202 -0
- package/lib/transaction/input/multisig.js +220 -0
- package/lib/transaction/input/multisigscripthash.js +189 -0
- package/lib/transaction/input/publickey.js +96 -0
- package/lib/transaction/input/publickeyhash.js +103 -0
- package/lib/transaction/output.js +192 -0
- package/lib/transaction/sighash.js +288 -0
- package/lib/transaction/signature.js +88 -0
- package/lib/transaction/transaction.js +1208 -0
- package/lib/transaction/unspentoutput.js +97 -0
- package/lib/util/_.js +44 -0
- package/lib/util/js.js +91 -0
- package/lib/util/preconditions.js +34 -0
- package/message/index.js +1 -0
- package/mnemonic/index.js +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
module.exports = require('./transaction')
|
|
2
|
+
|
|
3
|
+
module.exports.Input = require('./input')
|
|
4
|
+
module.exports.Output = require('./output')
|
|
5
|
+
module.exports.UnspentOutput = require('./unspentoutput')
|
|
6
|
+
module.exports.Signature = require('./signature')
|
|
7
|
+
module.exports.Sighash = require('./sighash')
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
module.exports = require('./input')
|
|
2
|
+
|
|
3
|
+
module.exports.PublicKey = require('./publickey')
|
|
4
|
+
module.exports.PublicKeyHash = require('./publickeyhash')
|
|
5
|
+
module.exports.MultiSig = require('./multisig.js')
|
|
6
|
+
module.exports.MultiSigScriptHash = require('./multisigscripthash.js')
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var _ = require('../../util/_')
|
|
4
|
+
var $ = require('../../util/preconditions')
|
|
5
|
+
var errors = require('../../errors')
|
|
6
|
+
var BufferWriter = require('../../encoding/bufferwriter')
|
|
7
|
+
var buffer = require('buffer')
|
|
8
|
+
var JSUtil = require('../../util/js')
|
|
9
|
+
var Script = require('../../script')
|
|
10
|
+
var Sighash = require('../sighash')
|
|
11
|
+
var Output = require('../output')
|
|
12
|
+
|
|
13
|
+
var MAXINT = 0xffffffff // Math.pow(2, 32) - 1;
|
|
14
|
+
var DEFAULT_RBF_SEQNUMBER = MAXINT - 2
|
|
15
|
+
var DEFAULT_SEQNUMBER = MAXINT
|
|
16
|
+
var DEFAULT_LOCKTIME_SEQNUMBER = MAXINT - 1
|
|
17
|
+
|
|
18
|
+
function Input (params) {
|
|
19
|
+
if (!(this instanceof Input)) {
|
|
20
|
+
return new Input(params)
|
|
21
|
+
}
|
|
22
|
+
if (params) {
|
|
23
|
+
return this._fromObject(params)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Input.MAXINT = MAXINT
|
|
28
|
+
Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER
|
|
29
|
+
Input.DEFAULT_LOCKTIME_SEQNUMBER = DEFAULT_LOCKTIME_SEQNUMBER
|
|
30
|
+
Input.DEFAULT_RBF_SEQNUMBER = DEFAULT_RBF_SEQNUMBER
|
|
31
|
+
// txid + output index + sequence number
|
|
32
|
+
Input.BASE_SIZE = 32 + 4 + 4
|
|
33
|
+
|
|
34
|
+
Object.defineProperty(Input.prototype, 'script', {
|
|
35
|
+
configurable: false,
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () {
|
|
38
|
+
if (this.isNull()) {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
if (!this._script) {
|
|
42
|
+
this._script = new Script(this._scriptBuffer)
|
|
43
|
+
this._script._isInput = true
|
|
44
|
+
}
|
|
45
|
+
return this._script
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
Input.fromObject = function (obj) {
|
|
50
|
+
$.checkArgument(_.isObject(obj))
|
|
51
|
+
var input = new Input()
|
|
52
|
+
return input._fromObject(obj)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Input.prototype._fromObject = function (params) {
|
|
56
|
+
var prevTxId
|
|
57
|
+
if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) {
|
|
58
|
+
prevTxId = buffer.Buffer.from(params.prevTxId, 'hex')
|
|
59
|
+
} else {
|
|
60
|
+
prevTxId = params.prevTxId
|
|
61
|
+
}
|
|
62
|
+
this.output = params.output
|
|
63
|
+
? (params.output instanceof Output ? params.output : new Output(params.output)) : undefined
|
|
64
|
+
this.prevTxId = prevTxId || params.txidbuf
|
|
65
|
+
this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex
|
|
66
|
+
this.sequenceNumber = _.isUndefined(params.sequenceNumber)
|
|
67
|
+
? (_.isUndefined(params.seqnum) ? DEFAULT_SEQNUMBER : params.seqnum) : params.sequenceNumber
|
|
68
|
+
if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) {
|
|
69
|
+
throw new errors.Transaction.Input.MissingScript()
|
|
70
|
+
}
|
|
71
|
+
this.setScript(params.scriptBuffer || params.script)
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Input.prototype.toObject = Input.prototype.toJSON = function toObject () {
|
|
76
|
+
var obj = {
|
|
77
|
+
prevTxId: this.prevTxId.toString('hex'),
|
|
78
|
+
outputIndex: this.outputIndex,
|
|
79
|
+
sequenceNumber: this.sequenceNumber,
|
|
80
|
+
script: this._scriptBuffer.toString('hex')
|
|
81
|
+
}
|
|
82
|
+
// add human readable form if input contains valid script
|
|
83
|
+
if (this.script) {
|
|
84
|
+
obj.scriptString = this.script.toString()
|
|
85
|
+
}
|
|
86
|
+
if (this.output) {
|
|
87
|
+
obj.output = this.output.toObject()
|
|
88
|
+
}
|
|
89
|
+
return obj
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Input.fromBufferReader = function (br) {
|
|
93
|
+
var input = new Input()
|
|
94
|
+
input.prevTxId = br.readReverse(32)
|
|
95
|
+
input.outputIndex = br.readUInt32LE()
|
|
96
|
+
input._scriptBuffer = br.readVarLengthBuffer()
|
|
97
|
+
input.sequenceNumber = br.readUInt32LE()
|
|
98
|
+
// TODO: return different classes according to which input it is
|
|
99
|
+
// e.g: CoinbaseInput, PublicKeyHashInput, MultiSigScriptHashInput, etc.
|
|
100
|
+
return input
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Input.prototype.toBufferWriter = function (writer) {
|
|
104
|
+
if (!writer) {
|
|
105
|
+
writer = new BufferWriter()
|
|
106
|
+
}
|
|
107
|
+
writer.writeReverse(this.prevTxId)
|
|
108
|
+
writer.writeUInt32LE(this.outputIndex)
|
|
109
|
+
var script = this._scriptBuffer
|
|
110
|
+
writer.writeVarintNum(script.length)
|
|
111
|
+
writer.write(script)
|
|
112
|
+
writer.writeUInt32LE(this.sequenceNumber)
|
|
113
|
+
return writer
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
Input.prototype.setScript = function (script) {
|
|
117
|
+
this._script = null
|
|
118
|
+
if (script instanceof Script) {
|
|
119
|
+
this._script = script
|
|
120
|
+
this._script._isInput = true
|
|
121
|
+
this._scriptBuffer = script.toBuffer()
|
|
122
|
+
} else if (script === null) {
|
|
123
|
+
this._script = Script.empty()
|
|
124
|
+
this._script._isInput = true
|
|
125
|
+
this._scriptBuffer = this._script.toBuffer()
|
|
126
|
+
} else if (JSUtil.isHexa(script)) {
|
|
127
|
+
// hex string script
|
|
128
|
+
this._scriptBuffer = buffer.Buffer.from(script, 'hex')
|
|
129
|
+
} else if (_.isString(script)) {
|
|
130
|
+
// human readable string script
|
|
131
|
+
this._script = new Script(script)
|
|
132
|
+
this._script._isInput = true
|
|
133
|
+
this._scriptBuffer = this._script.toBuffer()
|
|
134
|
+
} else if (Buffer.isBuffer(script)) {
|
|
135
|
+
// buffer script
|
|
136
|
+
this._scriptBuffer = buffer.Buffer.from(script)
|
|
137
|
+
} else {
|
|
138
|
+
throw new TypeError('Invalid argument type: script')
|
|
139
|
+
}
|
|
140
|
+
return this
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Retrieve signatures for the provided PrivateKey.
|
|
145
|
+
*
|
|
146
|
+
* @param {Transaction} transaction - the transaction to be signed
|
|
147
|
+
* @param {PrivateKey} privateKey - the private key to use when signing
|
|
148
|
+
* @param {number} inputIndex - the index of this input in the provided transaction
|
|
149
|
+
* @param {number} sigType - defaults to Signature.SIGHASH_ALL
|
|
150
|
+
* @param {Buffer} addressHash - if provided, don't calculate the hash of the
|
|
151
|
+
* public key associated with the private key provided
|
|
152
|
+
* @abstract
|
|
153
|
+
*/
|
|
154
|
+
Input.prototype.getSignatures = function () {
|
|
155
|
+
throw new errors.AbstractMethodInvoked(
|
|
156
|
+
'Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported)' +
|
|
157
|
+
' for input: ' + JSON.stringify(this)
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
Input.prototype.isFullySigned = function () {
|
|
162
|
+
throw new errors.AbstractMethodInvoked('Input#isFullySigned')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
Input.prototype.isFinal = function () {
|
|
166
|
+
return this.sequenceNumber === Input.MAXINT
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
Input.prototype.addSignature = function () {
|
|
170
|
+
throw new errors.AbstractMethodInvoked('Input#addSignature')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
Input.prototype.clearSignatures = function () {
|
|
174
|
+
throw new errors.AbstractMethodInvoked('Input#clearSignatures')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
Input.prototype.isValidSignature = function (transaction, signature) {
|
|
178
|
+
// FIXME: Refactor signature so this is not necessary
|
|
179
|
+
signature.signature.nhashtype = signature.sigtype
|
|
180
|
+
return Sighash.verify(
|
|
181
|
+
transaction,
|
|
182
|
+
signature.signature,
|
|
183
|
+
signature.publicKey,
|
|
184
|
+
signature.inputIndex,
|
|
185
|
+
this.output.script,
|
|
186
|
+
this.output.satoshisBN
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @returns true if this is a coinbase input (represents no input)
|
|
192
|
+
*/
|
|
193
|
+
Input.prototype.isNull = function () {
|
|
194
|
+
return this.prevTxId.toString('hex') === '0000000000000000000000000000000000000000000000000000000000000000' &&
|
|
195
|
+
this.outputIndex === 0xffffffff
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Input.prototype._estimateSize = function () {
|
|
199
|
+
return this.toBufferWriter().toBuffer().length
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = Input
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var _ = require('../../util/_')
|
|
4
|
+
var inherits = require('inherits')
|
|
5
|
+
var Input = require('./input')
|
|
6
|
+
var Output = require('../output')
|
|
7
|
+
var $ = require('../../util/preconditions')
|
|
8
|
+
|
|
9
|
+
var Script = require('../../script')
|
|
10
|
+
var Signature = require('../../crypto/signature')
|
|
11
|
+
var Sighash = require('../sighash')
|
|
12
|
+
var TransactionSignature = require('../signature')
|
|
13
|
+
var PublicKey = require('../../publickey')
|
|
14
|
+
var Varint = require('../../encoding/varint')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
19
|
+
function MultiSigInput (input, pubkeys, threshold, signatures) {
|
|
20
|
+
Input.apply(this, arguments)
|
|
21
|
+
var self = this
|
|
22
|
+
pubkeys = pubkeys || input.publicKeys
|
|
23
|
+
threshold = threshold || input.threshold
|
|
24
|
+
signatures = signatures || input.signatures
|
|
25
|
+
this.publicKeys = pubkeys.map(k => k.toString('hex')).sort().map(k => new PublicKey(k))
|
|
26
|
+
$.checkState(Script.buildMultisigOut(this.publicKeys, threshold).equals(this.output.script),
|
|
27
|
+
'Provided public keys don\'t match to the provided output script')
|
|
28
|
+
this.publicKeyIndex = {}
|
|
29
|
+
_.each(this.publicKeys, function (publicKey, index) {
|
|
30
|
+
self.publicKeyIndex[publicKey.toString()] = index
|
|
31
|
+
})
|
|
32
|
+
this.threshold = threshold
|
|
33
|
+
// Empty array of signatures
|
|
34
|
+
this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length)
|
|
35
|
+
}
|
|
36
|
+
inherits(MultiSigInput, Input)
|
|
37
|
+
|
|
38
|
+
MultiSigInput.prototype.toObject = function () {
|
|
39
|
+
var obj = Input.prototype.toObject.apply(this, arguments)
|
|
40
|
+
obj.threshold = this.threshold
|
|
41
|
+
obj.publicKeys = _.map(this.publicKeys, function (publicKey) { return publicKey.toString() })
|
|
42
|
+
obj.signatures = this._serializeSignatures()
|
|
43
|
+
return obj
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
MultiSigInput.prototype._deserializeSignatures = function (signatures) {
|
|
47
|
+
return _.map(signatures, function (signature) {
|
|
48
|
+
if (!signature) {
|
|
49
|
+
return undefined
|
|
50
|
+
}
|
|
51
|
+
return new TransactionSignature(signature)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
MultiSigInput.prototype._serializeSignatures = function () {
|
|
56
|
+
return _.map(this.signatures, function (signature) {
|
|
57
|
+
if (!signature) {
|
|
58
|
+
return undefined
|
|
59
|
+
}
|
|
60
|
+
return signature.toObject()
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
MultiSigInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype) {
|
|
65
|
+
$.checkState(this.output instanceof Output)
|
|
66
|
+
sigtype = sigtype || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
|
|
67
|
+
|
|
68
|
+
var self = this
|
|
69
|
+
var results = []
|
|
70
|
+
_.each(this.publicKeys, function (publicKey) {
|
|
71
|
+
if (publicKey.toString() === privateKey.publicKey.toString()) {
|
|
72
|
+
results.push(new TransactionSignature({
|
|
73
|
+
publicKey: privateKey.publicKey,
|
|
74
|
+
prevTxId: self.prevTxId,
|
|
75
|
+
outputIndex: self.outputIndex,
|
|
76
|
+
inputIndex: index,
|
|
77
|
+
signature: Sighash.sign(transaction, privateKey, sigtype, index, self.output.script, self.output.satoshisBN),
|
|
78
|
+
sigtype: sigtype
|
|
79
|
+
}))
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
return results
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
MultiSigInput.prototype.addSignature = function (transaction, signature) {
|
|
87
|
+
$.checkState(!this.isFullySigned(), 'All needed signatures have already been added')
|
|
88
|
+
$.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]),
|
|
89
|
+
'Signature has no matching public key')
|
|
90
|
+
$.checkState(this.isValidSignature(transaction, signature))
|
|
91
|
+
this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature
|
|
92
|
+
this._updateScript()
|
|
93
|
+
return this
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
MultiSigInput.prototype._updateScript = function () {
|
|
97
|
+
this.setScript(Script.buildMultisigIn(
|
|
98
|
+
this.publicKeys,
|
|
99
|
+
this.threshold,
|
|
100
|
+
this._createSignatures()
|
|
101
|
+
))
|
|
102
|
+
return this
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
MultiSigInput.prototype._createSignatures = function () {
|
|
106
|
+
return _.map(
|
|
107
|
+
_.filter(this.signatures, function (signature) { return !_.isUndefined(signature) }),
|
|
108
|
+
function (signature) {
|
|
109
|
+
return Buffer.concat([
|
|
110
|
+
signature.signature.toDER(),
|
|
111
|
+
Buffer.from([signature.sigtype & 0xff])
|
|
112
|
+
])
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
MultiSigInput.prototype.clearSignatures = function () {
|
|
118
|
+
this.signatures = new Array(this.publicKeys.length)
|
|
119
|
+
this._updateScript()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
MultiSigInput.prototype.isFullySigned = function () {
|
|
123
|
+
return this.countSignatures() === this.threshold
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
MultiSigInput.prototype.countMissingSignatures = function () {
|
|
127
|
+
return this.threshold - this.countSignatures()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
MultiSigInput.prototype.countSignatures = function () {
|
|
131
|
+
return _.reduce(this.signatures, function (sum, signature) {
|
|
132
|
+
return sum + (!!signature)
|
|
133
|
+
}, 0)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
MultiSigInput.prototype.publicKeysWithoutSignature = function () {
|
|
137
|
+
var self = this
|
|
138
|
+
return _.filter(this.publicKeys, function (publicKey) {
|
|
139
|
+
return !(self.signatures[self.publicKeyIndex[publicKey.toString()]])
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
MultiSigInput.prototype.isValidSignature = function (transaction, signature) {
|
|
144
|
+
// FIXME: Refactor signature so this is not necessary
|
|
145
|
+
signature.signature.nhashtype = signature.sigtype
|
|
146
|
+
return Sighash.verify(
|
|
147
|
+
transaction,
|
|
148
|
+
signature.signature,
|
|
149
|
+
signature.publicKey,
|
|
150
|
+
signature.inputIndex,
|
|
151
|
+
this.output.script,
|
|
152
|
+
this.output.satoshisBN
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
*
|
|
158
|
+
* @param {Buffer[]} signatures
|
|
159
|
+
* @param {PublicKey[]} publicKeys
|
|
160
|
+
* @param {Transaction} transaction
|
|
161
|
+
* @param {Integer} inputIndex
|
|
162
|
+
* @param {Input} input
|
|
163
|
+
* @returns {TransactionSignature[]}
|
|
164
|
+
*/
|
|
165
|
+
MultiSigInput.normalizeSignatures = function (transaction, input, inputIndex, signatures, publicKeys) {
|
|
166
|
+
return publicKeys.map(function (pubKey) {
|
|
167
|
+
var signatureMatch = null
|
|
168
|
+
signatures = signatures.filter(function (signatureBuffer) {
|
|
169
|
+
if (signatureMatch) {
|
|
170
|
+
return true
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var signature = new TransactionSignature({
|
|
174
|
+
signature: Signature.fromTxFormat(signatureBuffer),
|
|
175
|
+
publicKey: pubKey,
|
|
176
|
+
prevTxId: input.prevTxId,
|
|
177
|
+
outputIndex: input.outputIndex,
|
|
178
|
+
inputIndex: inputIndex,
|
|
179
|
+
sigtype: Signature.SIGHASH_ALL
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
signature.signature.nhashtype = signature.sigtype
|
|
183
|
+
var isMatch = Sighash.verify(
|
|
184
|
+
transaction,
|
|
185
|
+
signature.signature,
|
|
186
|
+
signature.publicKey,
|
|
187
|
+
signature.inputIndex,
|
|
188
|
+
input.output.script
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if (isMatch) {
|
|
192
|
+
signatureMatch = signature
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
return signatureMatch || null
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 32 txid
|
|
204
|
+
// 4 output index
|
|
205
|
+
// --- script ---
|
|
206
|
+
// ??? script size (VARINT)
|
|
207
|
+
// 1 OP_0
|
|
208
|
+
// --- signature list ---
|
|
209
|
+
// 1 signature size (OP_PUSHDATA)
|
|
210
|
+
// <=72 signature (DER + SIGHASH type)
|
|
211
|
+
//
|
|
212
|
+
// 4 sequence number
|
|
213
|
+
MultiSigInput.SIGNATURE_SIZE = 73
|
|
214
|
+
|
|
215
|
+
MultiSigInput.prototype._estimateSize = function () {
|
|
216
|
+
var scriptSize = 1 + this.threshold * MultiSigInput.SIGNATURE_SIZE
|
|
217
|
+
return Input.BASE_SIZE + Varint(scriptSize).toBuffer().length + scriptSize
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = MultiSigInput
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var _ = require('../../util/_')
|
|
4
|
+
var inherits = require('inherits')
|
|
5
|
+
var Input = require('./input')
|
|
6
|
+
var Output = require('../output')
|
|
7
|
+
var $ = require('../../util/preconditions')
|
|
8
|
+
|
|
9
|
+
var Script = require('../../script')
|
|
10
|
+
var Signature = require('../../crypto/signature')
|
|
11
|
+
var Sighash = require('../sighash')
|
|
12
|
+
var TransactionSignature = require('../signature')
|
|
13
|
+
var PublicKey = require('../../publickey')
|
|
14
|
+
var Varint = require('../../encoding/varint')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
19
|
+
function MultiSigScriptHashInput (input, pubkeys, threshold, signatures) {
|
|
20
|
+
Input.apply(this, arguments)
|
|
21
|
+
var self = this
|
|
22
|
+
pubkeys = pubkeys || input.publicKeys
|
|
23
|
+
threshold = threshold || input.threshold
|
|
24
|
+
signatures = signatures || input.signatures
|
|
25
|
+
this.publicKeys = pubkeys.map(k => k.toString('hex')).sort().map(k => new PublicKey(k))
|
|
26
|
+
this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold)
|
|
27
|
+
$.checkState(Script.buildScriptHashOut(this.redeemScript).equals(this.output.script),
|
|
28
|
+
'Provided public keys don\'t hash to the provided output')
|
|
29
|
+
this.publicKeyIndex = {}
|
|
30
|
+
_.each(this.publicKeys, function (publicKey, index) {
|
|
31
|
+
self.publicKeyIndex[publicKey.toString()] = index
|
|
32
|
+
})
|
|
33
|
+
this.threshold = threshold
|
|
34
|
+
// Empty array of signatures
|
|
35
|
+
this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length)
|
|
36
|
+
}
|
|
37
|
+
inherits(MultiSigScriptHashInput, Input)
|
|
38
|
+
|
|
39
|
+
MultiSigScriptHashInput.prototype.toObject = function () {
|
|
40
|
+
var obj = Input.prototype.toObject.apply(this, arguments)
|
|
41
|
+
obj.threshold = this.threshold
|
|
42
|
+
obj.publicKeys = _.map(this.publicKeys, function (publicKey) { return publicKey.toString() })
|
|
43
|
+
obj.signatures = this._serializeSignatures()
|
|
44
|
+
return obj
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
MultiSigScriptHashInput.prototype._deserializeSignatures = function (signatures) {
|
|
48
|
+
return _.map(signatures, function (signature) {
|
|
49
|
+
if (!signature) {
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
52
|
+
return new TransactionSignature(signature)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
MultiSigScriptHashInput.prototype._serializeSignatures = function () {
|
|
57
|
+
return _.map(this.signatures, function (signature) {
|
|
58
|
+
if (!signature) {
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
return signature.toObject()
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
MultiSigScriptHashInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype) {
|
|
66
|
+
$.checkState(this.output instanceof Output)
|
|
67
|
+
sigtype = sigtype || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
|
|
68
|
+
|
|
69
|
+
var self = this
|
|
70
|
+
var results = []
|
|
71
|
+
_.each(this.publicKeys, function (publicKey) {
|
|
72
|
+
if (publicKey.toString() === privateKey.publicKey.toString()) {
|
|
73
|
+
results.push(new TransactionSignature({
|
|
74
|
+
publicKey: privateKey.publicKey,
|
|
75
|
+
prevTxId: self.prevTxId,
|
|
76
|
+
outputIndex: self.outputIndex,
|
|
77
|
+
inputIndex: index,
|
|
78
|
+
signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript, self.output.satoshisBN),
|
|
79
|
+
sigtype: sigtype
|
|
80
|
+
}))
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
return results
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
MultiSigScriptHashInput.prototype.addSignature = function (transaction, signature) {
|
|
87
|
+
$.checkState(!this.isFullySigned(), 'All needed signatures have already been added')
|
|
88
|
+
$.checkArgument(!_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]),
|
|
89
|
+
'Signature has no matching public key')
|
|
90
|
+
$.checkState(this.isValidSignature(transaction, signature))
|
|
91
|
+
this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature
|
|
92
|
+
this._updateScript()
|
|
93
|
+
return this
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
MultiSigScriptHashInput.prototype._updateScript = function () {
|
|
97
|
+
this.setScript(Script.buildP2SHMultisigIn(
|
|
98
|
+
this.publicKeys,
|
|
99
|
+
this.threshold,
|
|
100
|
+
this._createSignatures(),
|
|
101
|
+
{ cachedMultisig: this.redeemScript }
|
|
102
|
+
))
|
|
103
|
+
return this
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
MultiSigScriptHashInput.prototype._createSignatures = function () {
|
|
107
|
+
return _.map(
|
|
108
|
+
_.filter(this.signatures, function (signature) { return !_.isUndefined(signature) }),
|
|
109
|
+
function (signature) {
|
|
110
|
+
return Buffer.concat([
|
|
111
|
+
signature.signature.toDER(),
|
|
112
|
+
Buffer.from([signature.sigtype & 0xff])
|
|
113
|
+
])
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
MultiSigScriptHashInput.prototype.clearSignatures = function () {
|
|
119
|
+
this.signatures = new Array(this.publicKeys.length)
|
|
120
|
+
this._updateScript()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
MultiSigScriptHashInput.prototype.isFullySigned = function () {
|
|
124
|
+
return this.countSignatures() === this.threshold
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
MultiSigScriptHashInput.prototype.countMissingSignatures = function () {
|
|
128
|
+
return this.threshold - this.countSignatures()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
MultiSigScriptHashInput.prototype.countSignatures = function () {
|
|
132
|
+
return _.reduce(this.signatures, function (sum, signature) {
|
|
133
|
+
return sum + (!!signature)
|
|
134
|
+
}, 0)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function () {
|
|
138
|
+
var self = this
|
|
139
|
+
return _.filter(this.publicKeys, function (publicKey) {
|
|
140
|
+
return !(self.signatures[self.publicKeyIndex[publicKey.toString()]])
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
MultiSigScriptHashInput.prototype.isValidSignature = function (transaction, signature) {
|
|
145
|
+
// FIXME: Refactor signature so this is not necessary
|
|
146
|
+
signature.signature.nhashtype = signature.sigtype
|
|
147
|
+
return Sighash.verify(
|
|
148
|
+
transaction,
|
|
149
|
+
signature.signature,
|
|
150
|
+
signature.publicKey,
|
|
151
|
+
signature.inputIndex,
|
|
152
|
+
this.redeemScript,
|
|
153
|
+
this.output.satoshisBN
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 32 txid
|
|
158
|
+
// 4 output index
|
|
159
|
+
// --- script ---
|
|
160
|
+
// ??? script size (VARINT)
|
|
161
|
+
// 1 OP_0
|
|
162
|
+
// --- signature list ---
|
|
163
|
+
// 1 signature size (OP_PUSHDATA)
|
|
164
|
+
// <=72 signature (DER + SIGHASH type)
|
|
165
|
+
//
|
|
166
|
+
// ??? redeem script size (OP_PUSHDATA)
|
|
167
|
+
// --- redeem script ---
|
|
168
|
+
// 1 OP_2
|
|
169
|
+
// --- public key list ---
|
|
170
|
+
// 1 public key size (OP_PUSHDATA)
|
|
171
|
+
// 33 compressed public key
|
|
172
|
+
//
|
|
173
|
+
// 1 OP_3
|
|
174
|
+
// 1 OP_CHECKMULTISIG
|
|
175
|
+
//
|
|
176
|
+
// 4 sequence number
|
|
177
|
+
MultiSigScriptHashInput.SIGNATURE_SIZE = 73
|
|
178
|
+
MultiSigScriptHashInput.PUBKEY_SIZE = 34
|
|
179
|
+
|
|
180
|
+
MultiSigScriptHashInput.prototype._estimateSize = function () {
|
|
181
|
+
var pubKeysSize = this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE
|
|
182
|
+
var sigsSize = this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE
|
|
183
|
+
var redeemScriptSize = 3 + pubKeysSize
|
|
184
|
+
var redeemScriptPushdataSize = redeemScriptSize <= 75 ? 1 : redeemScriptSize <= 255 ? 2 : 3
|
|
185
|
+
var scriptLength = sigsSize + 1 + redeemScriptPushdataSize + redeemScriptSize
|
|
186
|
+
return Input.BASE_SIZE + Varint(scriptLength).toBuffer().length + scriptLength
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = MultiSigScriptHashInput
|