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,96 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var inherits = require('inherits')
|
|
4
|
+
|
|
5
|
+
var $ = require('../../util/preconditions')
|
|
6
|
+
|
|
7
|
+
var Input = require('./input')
|
|
8
|
+
var Output = require('../output')
|
|
9
|
+
var Sighash = require('../sighash')
|
|
10
|
+
var Script = require('../../script')
|
|
11
|
+
var Signature = require('../../crypto/signature')
|
|
12
|
+
var TransactionSignature = require('../signature')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Represents a special kind of input of PayToPublicKey kind.
|
|
16
|
+
* @constructor
|
|
17
|
+
*/
|
|
18
|
+
function PublicKeyInput () {
|
|
19
|
+
Input.apply(this, arguments)
|
|
20
|
+
}
|
|
21
|
+
inherits(PublicKeyInput, Input)
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Transaction} transaction - the transaction to be signed
|
|
25
|
+
* @param {PrivateKey} privateKey - the private key with which to sign the transaction
|
|
26
|
+
* @param {number} index - the index of the input in the transaction input vector
|
|
27
|
+
* @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL
|
|
28
|
+
* @return {Array} of objects that can be
|
|
29
|
+
*/
|
|
30
|
+
PublicKeyInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype) {
|
|
31
|
+
$.checkState(this.output instanceof Output)
|
|
32
|
+
sigtype = sigtype || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
|
|
33
|
+
var publicKey = privateKey.toPublicKey()
|
|
34
|
+
if (publicKey.toString() === this.output.script.getPublicKey().toString('hex')) {
|
|
35
|
+
return [new TransactionSignature({
|
|
36
|
+
publicKey: publicKey,
|
|
37
|
+
prevTxId: this.prevTxId,
|
|
38
|
+
outputIndex: this.outputIndex,
|
|
39
|
+
inputIndex: index,
|
|
40
|
+
signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script, this.output.satoshisBN),
|
|
41
|
+
sigtype: sigtype
|
|
42
|
+
})]
|
|
43
|
+
}
|
|
44
|
+
return []
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Add the provided signature
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} signature
|
|
51
|
+
* @param {PublicKey} signature.publicKey
|
|
52
|
+
* @param {Signature} signature.signature
|
|
53
|
+
* @param {number=} signature.sigtype
|
|
54
|
+
* @return {PublicKeyInput} this, for chaining
|
|
55
|
+
*/
|
|
56
|
+
PublicKeyInput.prototype.addSignature = function (transaction, signature) {
|
|
57
|
+
$.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid')
|
|
58
|
+
this.setScript(Script.buildPublicKeyIn(
|
|
59
|
+
signature.signature.toDER(),
|
|
60
|
+
signature.sigtype
|
|
61
|
+
))
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Clear the input's signature
|
|
67
|
+
* @return {PublicKeyHashInput} this, for chaining
|
|
68
|
+
*/
|
|
69
|
+
PublicKeyInput.prototype.clearSignatures = function () {
|
|
70
|
+
this.setScript(Script.empty())
|
|
71
|
+
return this
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Query whether the input is signed
|
|
76
|
+
* @return {boolean}
|
|
77
|
+
*/
|
|
78
|
+
PublicKeyInput.prototype.isFullySigned = function () {
|
|
79
|
+
return this.script.isPublicKeyIn()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 32 txid
|
|
83
|
+
// 4 output index
|
|
84
|
+
// ---
|
|
85
|
+
// 1 script size (VARINT)
|
|
86
|
+
// 1 signature size (OP_PUSHDATA)
|
|
87
|
+
// <=72 signature (DER + SIGHASH type)
|
|
88
|
+
// ---
|
|
89
|
+
// 4 sequence number
|
|
90
|
+
PublicKeyInput.SCRIPT_MAX_SIZE = 74
|
|
91
|
+
|
|
92
|
+
PublicKeyInput.prototype._estimateSize = function () {
|
|
93
|
+
return Input.BASE_SIZE + PublicKeyInput.SCRIPT_MAX_SIZE
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = PublicKeyInput
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var inherits = require('inherits')
|
|
4
|
+
|
|
5
|
+
var $ = require('../../util/preconditions')
|
|
6
|
+
|
|
7
|
+
var Hash = require('../../crypto/hash')
|
|
8
|
+
var Input = require('./input')
|
|
9
|
+
var Output = require('../output')
|
|
10
|
+
var Sighash = require('../sighash')
|
|
11
|
+
var Script = require('../../script')
|
|
12
|
+
var Signature = require('../../crypto/signature')
|
|
13
|
+
var TransactionSignature = require('../signature')
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents a special kind of input of PayToPublicKeyHash kind.
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
19
|
+
function PublicKeyHashInput () {
|
|
20
|
+
Input.apply(this, arguments)
|
|
21
|
+
}
|
|
22
|
+
inherits(PublicKeyHashInput, Input)
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Transaction} transaction - the transaction to be signed
|
|
26
|
+
* @param {PrivateKey} privateKey - the private key with which to sign the transaction
|
|
27
|
+
* @param {number} index - the index of the input in the transaction input vector
|
|
28
|
+
* @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL
|
|
29
|
+
* @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided
|
|
30
|
+
* @return {Array} of objects that can be
|
|
31
|
+
*/
|
|
32
|
+
PublicKeyHashInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype, hashData) {
|
|
33
|
+
$.checkState(this.output instanceof Output)
|
|
34
|
+
hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer())
|
|
35
|
+
sigtype = sigtype || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
|
|
36
|
+
|
|
37
|
+
if (hashData.equals(this.output.script.getPublicKeyHash())) {
|
|
38
|
+
return [new TransactionSignature({
|
|
39
|
+
publicKey: privateKey.publicKey,
|
|
40
|
+
prevTxId: this.prevTxId,
|
|
41
|
+
outputIndex: this.outputIndex,
|
|
42
|
+
inputIndex: index,
|
|
43
|
+
signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script, this.output.satoshisBN),
|
|
44
|
+
sigtype: sigtype
|
|
45
|
+
})]
|
|
46
|
+
}
|
|
47
|
+
return []
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Add the provided signature
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} signature
|
|
54
|
+
* @param {PublicKey} signature.publicKey
|
|
55
|
+
* @param {Signature} signature.signature
|
|
56
|
+
* @param {number=} signature.sigtype
|
|
57
|
+
* @return {PublicKeyHashInput} this, for chaining
|
|
58
|
+
*/
|
|
59
|
+
PublicKeyHashInput.prototype.addSignature = function (transaction, signature) {
|
|
60
|
+
$.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid')
|
|
61
|
+
|
|
62
|
+
this.setScript(Script.buildPublicKeyHashIn(
|
|
63
|
+
signature.publicKey,
|
|
64
|
+
signature.signature.toDER(),
|
|
65
|
+
signature.sigtype
|
|
66
|
+
))
|
|
67
|
+
return this
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Clear the input's signature
|
|
72
|
+
* @return {PublicKeyHashInput} this, for chaining
|
|
73
|
+
*/
|
|
74
|
+
PublicKeyHashInput.prototype.clearSignatures = function () {
|
|
75
|
+
this.setScript(Script.empty())
|
|
76
|
+
return this
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Query whether the input is signed
|
|
81
|
+
* @return {boolean}
|
|
82
|
+
*/
|
|
83
|
+
PublicKeyHashInput.prototype.isFullySigned = function () {
|
|
84
|
+
return this.script.isPublicKeyHashIn()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 32 txid
|
|
88
|
+
// 4 output index
|
|
89
|
+
// --- script ---
|
|
90
|
+
// 1 script size (VARINT)
|
|
91
|
+
// 1 signature size (OP_PUSHDATA)
|
|
92
|
+
// <=72 signature (DER + SIGHASH type)
|
|
93
|
+
// 1 public key size (OP_PUSHDATA)
|
|
94
|
+
// 33 compressed public key
|
|
95
|
+
//
|
|
96
|
+
// 4 sequence number
|
|
97
|
+
PublicKeyHashInput.SCRIPT_MAX_SIZE = 108
|
|
98
|
+
|
|
99
|
+
PublicKeyHashInput.prototype._estimateSize = function () {
|
|
100
|
+
return Input.BASE_SIZE + PublicKeyHashInput.SCRIPT_MAX_SIZE
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = PublicKeyHashInput
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var _ = require('../util/_')
|
|
4
|
+
var BN = require('../crypto/bn')
|
|
5
|
+
var buffer = require('buffer')
|
|
6
|
+
var JSUtil = require('../util/js')
|
|
7
|
+
var BufferWriter = require('../encoding/bufferwriter')
|
|
8
|
+
var Varint = require('../encoding/varint')
|
|
9
|
+
var Script = require('../script')
|
|
10
|
+
var $ = require('../util/preconditions')
|
|
11
|
+
var errors = require('../errors')
|
|
12
|
+
|
|
13
|
+
var MAX_SAFE_INTEGER = 0x1fffffffffffff
|
|
14
|
+
|
|
15
|
+
function Output (args) {
|
|
16
|
+
if (!(this instanceof Output)) {
|
|
17
|
+
return new Output(args)
|
|
18
|
+
}
|
|
19
|
+
if (_.isObject(args)) {
|
|
20
|
+
this.satoshis = args.satoshis
|
|
21
|
+
if (Buffer.isBuffer(args.script)) {
|
|
22
|
+
this._scriptBuffer = args.script
|
|
23
|
+
} else {
|
|
24
|
+
var script
|
|
25
|
+
if (_.isString(args.script) && JSUtil.isHexa(args.script)) {
|
|
26
|
+
script = buffer.Buffer.from(args.script, 'hex')
|
|
27
|
+
} else {
|
|
28
|
+
script = args.script
|
|
29
|
+
}
|
|
30
|
+
this.setScript(script)
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
throw new TypeError('Unrecognized argument for Output')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Object.defineProperty(Output.prototype, 'script', {
|
|
38
|
+
configurable: false,
|
|
39
|
+
enumerable: true,
|
|
40
|
+
get: function () {
|
|
41
|
+
if (this._script) {
|
|
42
|
+
return this._script
|
|
43
|
+
} else {
|
|
44
|
+
this.setScriptFromBuffer(this._scriptBuffer)
|
|
45
|
+
return this._script
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
Object.defineProperty(Output.prototype, 'satoshis', {
|
|
51
|
+
configurable: false,
|
|
52
|
+
enumerable: true,
|
|
53
|
+
get: function () {
|
|
54
|
+
return this._satoshis
|
|
55
|
+
},
|
|
56
|
+
set: function (num) {
|
|
57
|
+
if (num instanceof BN) {
|
|
58
|
+
this._satoshisBN = num
|
|
59
|
+
this._satoshis = num.toNumber()
|
|
60
|
+
} else if (_.isString(num)) {
|
|
61
|
+
this._satoshis = parseInt(num)
|
|
62
|
+
this._satoshisBN = BN.fromNumber(this._satoshis)
|
|
63
|
+
} else {
|
|
64
|
+
$.checkArgument(
|
|
65
|
+
JSUtil.isNaturalNumber(num),
|
|
66
|
+
'Output satoshis is not a natural number'
|
|
67
|
+
)
|
|
68
|
+
this._satoshisBN = BN.fromNumber(num)
|
|
69
|
+
this._satoshis = num
|
|
70
|
+
}
|
|
71
|
+
$.checkState(
|
|
72
|
+
JSUtil.isNaturalNumber(this._satoshis),
|
|
73
|
+
'Output satoshis is not a natural number'
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
Output.prototype.invalidSatoshis = function () {
|
|
79
|
+
if (this._satoshis > MAX_SAFE_INTEGER) {
|
|
80
|
+
return 'transaction txout satoshis greater than max safe integer'
|
|
81
|
+
}
|
|
82
|
+
if (this._satoshis !== this._satoshisBN.toNumber()) {
|
|
83
|
+
return 'transaction txout satoshis has corrupted value'
|
|
84
|
+
}
|
|
85
|
+
if (this._satoshis < 0) {
|
|
86
|
+
return 'transaction txout negative'
|
|
87
|
+
}
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Object.defineProperty(Output.prototype, 'satoshisBN', {
|
|
92
|
+
configurable: false,
|
|
93
|
+
enumerable: true,
|
|
94
|
+
get: function () {
|
|
95
|
+
return this._satoshisBN
|
|
96
|
+
},
|
|
97
|
+
set: function (num) {
|
|
98
|
+
this._satoshisBN = num
|
|
99
|
+
this._satoshis = num.toNumber()
|
|
100
|
+
$.checkState(
|
|
101
|
+
JSUtil.isNaturalNumber(this._satoshis),
|
|
102
|
+
'Output satoshis is not a natural number'
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
Output.prototype.toObject = Output.prototype.toJSON = function toObject () {
|
|
108
|
+
var obj = {
|
|
109
|
+
satoshis: this.satoshis
|
|
110
|
+
}
|
|
111
|
+
obj.script = this._scriptBuffer.toString('hex')
|
|
112
|
+
return obj
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Output.fromObject = function (data) {
|
|
116
|
+
return new Output(data)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Output.prototype.setScriptFromBuffer = function (buffer) {
|
|
120
|
+
this._scriptBuffer = buffer
|
|
121
|
+
try {
|
|
122
|
+
this._script = Script.fromBuffer(this._scriptBuffer)
|
|
123
|
+
this._script._isOutput = true
|
|
124
|
+
} catch (e) {
|
|
125
|
+
if (e instanceof errors.Script.InvalidBuffer) {
|
|
126
|
+
this._script = null
|
|
127
|
+
} else {
|
|
128
|
+
throw e
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Output.prototype.setScript = function (script) {
|
|
134
|
+
if (script instanceof Script) {
|
|
135
|
+
this._scriptBuffer = script.toBuffer()
|
|
136
|
+
this._script = script
|
|
137
|
+
this._script._isOutput = true
|
|
138
|
+
} else if (_.isString(script)) {
|
|
139
|
+
this._script = Script.fromString(script)
|
|
140
|
+
this._scriptBuffer = this._script.toBuffer()
|
|
141
|
+
this._script._isOutput = true
|
|
142
|
+
} else if (Buffer.isBuffer(script)) {
|
|
143
|
+
this.setScriptFromBuffer(script)
|
|
144
|
+
} else {
|
|
145
|
+
throw new TypeError('Invalid argument type: script')
|
|
146
|
+
}
|
|
147
|
+
return this
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Output.prototype.inspect = function () {
|
|
151
|
+
var scriptStr
|
|
152
|
+
if (this.script) {
|
|
153
|
+
scriptStr = this.script.inspect()
|
|
154
|
+
} else {
|
|
155
|
+
scriptStr = this._scriptBuffer.toString('hex')
|
|
156
|
+
}
|
|
157
|
+
return '<Output (' + this.satoshis + ' sats) ' + scriptStr + '>'
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Output.fromBufferReader = function (br) {
|
|
161
|
+
var obj = {}
|
|
162
|
+
obj.satoshis = br.readUInt64LEBN()
|
|
163
|
+
var size = br.readVarintNum()
|
|
164
|
+
if (size !== 0) {
|
|
165
|
+
obj.script = br.read(size)
|
|
166
|
+
} else {
|
|
167
|
+
obj.script = buffer.Buffer.from([])
|
|
168
|
+
}
|
|
169
|
+
return new Output(obj)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Output.prototype.toBufferWriter = function (writer) {
|
|
173
|
+
if (!writer) {
|
|
174
|
+
writer = new BufferWriter()
|
|
175
|
+
}
|
|
176
|
+
writer.writeUInt64LEBN(this._satoshisBN)
|
|
177
|
+
var script = this._scriptBuffer
|
|
178
|
+
writer.writeVarintNum(script.length)
|
|
179
|
+
writer.write(script)
|
|
180
|
+
return writer
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 8 value
|
|
184
|
+
// ??? script size (VARINT)
|
|
185
|
+
// ??? script
|
|
186
|
+
Output.prototype.getSize = function () {
|
|
187
|
+
var scriptSize = this.script.toBuffer().length
|
|
188
|
+
var varintSize = Varint(scriptSize).toBuffer().length
|
|
189
|
+
return 8 + varintSize + scriptSize
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = Output
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var buffer = require('buffer')
|
|
4
|
+
|
|
5
|
+
var Signature = require('../crypto/signature')
|
|
6
|
+
var Script = require('../script')
|
|
7
|
+
var Output = require('./output')
|
|
8
|
+
var BufferReader = require('../encoding/bufferreader')
|
|
9
|
+
var BufferWriter = require('../encoding/bufferwriter')
|
|
10
|
+
var BN = require('../crypto/bn')
|
|
11
|
+
var Hash = require('../crypto/hash')
|
|
12
|
+
var ECDSA = require('../crypto/ecdsa')
|
|
13
|
+
var $ = require('../util/preconditions')
|
|
14
|
+
var Interpreter = require('../script/interpreter')
|
|
15
|
+
var _ = require('../util/_')
|
|
16
|
+
|
|
17
|
+
var SIGHASH_SINGLE_BUG = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex')
|
|
18
|
+
var BITS_64_ON = 'ffffffffffffffff'
|
|
19
|
+
|
|
20
|
+
// By default, we sign with sighash_forkid
|
|
21
|
+
var DEFAULT_SIGN_FLAGS = Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
22
|
+
|
|
23
|
+
var sighashPreimageForForkId = function (transaction, sighashType, inputNumber, subscript, satoshisBN) {
|
|
24
|
+
var input = transaction.inputs[inputNumber]
|
|
25
|
+
$.checkArgument(
|
|
26
|
+
satoshisBN instanceof BN,
|
|
27
|
+
'For ForkId=0 signatures, satoshis or complete input must be provided'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function GetPrevoutHash (tx) {
|
|
31
|
+
var writer = new BufferWriter()
|
|
32
|
+
|
|
33
|
+
_.each(tx.inputs, function (input) {
|
|
34
|
+
writer.writeReverse(input.prevTxId)
|
|
35
|
+
writer.writeUInt32LE(input.outputIndex)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
var buf = writer.toBuffer()
|
|
39
|
+
var ret = Hash.sha256sha256(buf)
|
|
40
|
+
return ret
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function GetSequenceHash (tx) {
|
|
44
|
+
var writer = new BufferWriter()
|
|
45
|
+
|
|
46
|
+
_.each(tx.inputs, function (input) {
|
|
47
|
+
writer.writeUInt32LE(input.sequenceNumber)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
var buf = writer.toBuffer()
|
|
51
|
+
var ret = Hash.sha256sha256(buf)
|
|
52
|
+
return ret
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function GetOutputsHash (tx, n) {
|
|
56
|
+
var writer = new BufferWriter()
|
|
57
|
+
|
|
58
|
+
if (_.isUndefined(n)) {
|
|
59
|
+
_.each(tx.outputs, function (output) {
|
|
60
|
+
output.toBufferWriter(writer)
|
|
61
|
+
})
|
|
62
|
+
} else {
|
|
63
|
+
tx.outputs[n].toBufferWriter(writer)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var buf = writer.toBuffer()
|
|
67
|
+
var ret = Hash.sha256sha256(buf)
|
|
68
|
+
return ret
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var hashPrevouts = Buffer.alloc(32)
|
|
72
|
+
var hashSequence = Buffer.alloc(32)
|
|
73
|
+
var hashOutputs = Buffer.alloc(32)
|
|
74
|
+
|
|
75
|
+
if (!(sighashType & Signature.SIGHASH_ANYONECANPAY)) {
|
|
76
|
+
hashPrevouts = GetPrevoutHash(transaction)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!(sighashType & Signature.SIGHASH_ANYONECANPAY) &&
|
|
80
|
+
(sighashType & 31) !== Signature.SIGHASH_SINGLE &&
|
|
81
|
+
(sighashType & 31) !== Signature.SIGHASH_NONE) {
|
|
82
|
+
hashSequence = GetSequenceHash(transaction)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if ((sighashType & 31) !== Signature.SIGHASH_SINGLE && (sighashType & 31) !== Signature.SIGHASH_NONE) {
|
|
86
|
+
hashOutputs = GetOutputsHash(transaction)
|
|
87
|
+
} else if ((sighashType & 31) === Signature.SIGHASH_SINGLE && inputNumber < transaction.outputs.length) {
|
|
88
|
+
hashOutputs = GetOutputsHash(transaction, inputNumber)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var writer = new BufferWriter()
|
|
92
|
+
|
|
93
|
+
// Version
|
|
94
|
+
writer.writeInt32LE(transaction.version)
|
|
95
|
+
|
|
96
|
+
// Input prevouts/nSequence (none/all, depending on flags)
|
|
97
|
+
writer.write(hashPrevouts)
|
|
98
|
+
writer.write(hashSequence)
|
|
99
|
+
|
|
100
|
+
// outpoint (32-byte hash + 4-byte little endian)
|
|
101
|
+
writer.writeReverse(input.prevTxId)
|
|
102
|
+
writer.writeUInt32LE(input.outputIndex)
|
|
103
|
+
|
|
104
|
+
// scriptCode of the input (serialized as scripts inside CTxOuts)
|
|
105
|
+
writer.writeVarintNum(subscript.toBuffer().length)
|
|
106
|
+
writer.write(subscript.toBuffer())
|
|
107
|
+
|
|
108
|
+
// value of the output spent by this input (8-byte little endian)
|
|
109
|
+
writer.writeUInt64LEBN(satoshisBN)
|
|
110
|
+
|
|
111
|
+
// nSequence of the input (4-byte little endian)
|
|
112
|
+
var sequenceNumber = input.sequenceNumber
|
|
113
|
+
writer.writeUInt32LE(sequenceNumber)
|
|
114
|
+
|
|
115
|
+
// Outputs (none/one/all, depending on flags)
|
|
116
|
+
writer.write(hashOutputs)
|
|
117
|
+
|
|
118
|
+
// Locktime
|
|
119
|
+
writer.writeUInt32LE(transaction.nLockTime)
|
|
120
|
+
|
|
121
|
+
// sighashType
|
|
122
|
+
writer.writeUInt32LE(sighashType >>> 0)
|
|
123
|
+
|
|
124
|
+
var buf = writer.toBuffer()
|
|
125
|
+
return buf
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns a buffer with the which is hashed with sighash that needs to be signed
|
|
130
|
+
* for OP_CHECKSIG.
|
|
131
|
+
*
|
|
132
|
+
* @name Signing.sighash
|
|
133
|
+
* @param {Transaction} transaction the transaction to sign
|
|
134
|
+
* @param {number} sighashType the type of the hash
|
|
135
|
+
* @param {number} inputNumber the input index for the signature
|
|
136
|
+
* @param {Script} subscript the script that will be signed
|
|
137
|
+
* @param {satoshisBN} input's amount (for ForkId signatures)
|
|
138
|
+
*
|
|
139
|
+
*/
|
|
140
|
+
var sighashPreimage = function sighashPreimage (transaction, sighashType, inputNumber, subscript, satoshisBN, flags) {
|
|
141
|
+
var Transaction = require('./transaction')
|
|
142
|
+
var Input = require('./input')
|
|
143
|
+
|
|
144
|
+
if (_.isUndefined(flags)) {
|
|
145
|
+
flags = DEFAULT_SIGN_FLAGS
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Copy transaction
|
|
149
|
+
var txcopy = Transaction.shallowCopy(transaction)
|
|
150
|
+
|
|
151
|
+
// Copy script
|
|
152
|
+
subscript = new Script(subscript)
|
|
153
|
+
|
|
154
|
+
if (flags & Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION) {
|
|
155
|
+
// Legacy chain's value for fork id must be of the form 0xffxxxx.
|
|
156
|
+
// By xoring with 0xdead, we ensure that the value will be different
|
|
157
|
+
// from the original one, even if it already starts with 0xff.
|
|
158
|
+
var forkValue = sighashType >> 8
|
|
159
|
+
var newForkValue = 0xff0000 | (forkValue ^ 0xdead)
|
|
160
|
+
sighashType = (newForkValue << 8) | (sighashType & 0xff)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if ((sighashType & Signature.SIGHASH_FORKID) && (flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID)) {
|
|
164
|
+
return sighashPreimageForForkId(txcopy, sighashType, inputNumber, subscript, satoshisBN)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// For no ForkId sighash, separators need to be removed.
|
|
168
|
+
subscript.removeCodeseparators()
|
|
169
|
+
|
|
170
|
+
var i
|
|
171
|
+
|
|
172
|
+
for (i = 0; i < txcopy.inputs.length; i++) {
|
|
173
|
+
// Blank signatures for other inputs
|
|
174
|
+
txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty())
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript)
|
|
178
|
+
|
|
179
|
+
if ((sighashType & 31) === Signature.SIGHASH_NONE ||
|
|
180
|
+
(sighashType & 31) === Signature.SIGHASH_SINGLE) {
|
|
181
|
+
// clear all sequenceNumbers
|
|
182
|
+
for (i = 0; i < txcopy.inputs.length; i++) {
|
|
183
|
+
if (i !== inputNumber) {
|
|
184
|
+
txcopy.inputs[i].sequenceNumber = 0
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if ((sighashType & 31) === Signature.SIGHASH_NONE) {
|
|
190
|
+
txcopy.outputs = []
|
|
191
|
+
} else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) {
|
|
192
|
+
// The SIGHASH_SINGLE bug.
|
|
193
|
+
// https://bitcointalk.org/index.php?topic=260595.0
|
|
194
|
+
if (inputNumber >= txcopy.outputs.length) {
|
|
195
|
+
return SIGHASH_SINGLE_BUG
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
txcopy.outputs.length = inputNumber + 1
|
|
199
|
+
|
|
200
|
+
for (i = 0; i < inputNumber; i++) {
|
|
201
|
+
txcopy.outputs[i] = new Output({
|
|
202
|
+
satoshis: BN.fromBuffer(buffer.Buffer.from(BITS_64_ON, 'hex')),
|
|
203
|
+
script: Script.empty()
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (sighashType & Signature.SIGHASH_ANYONECANPAY) {
|
|
209
|
+
txcopy.inputs = [txcopy.inputs[inputNumber]]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
var buf = new BufferWriter()
|
|
213
|
+
.write(txcopy.toBuffer())
|
|
214
|
+
.writeInt32LE(sighashType)
|
|
215
|
+
.toBuffer()
|
|
216
|
+
return buf
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Returns a buffer of length 32 bytes with the hash that needs to be signed
|
|
221
|
+
* for OP_CHECKSIG.
|
|
222
|
+
*
|
|
223
|
+
* @name Signing.sighash
|
|
224
|
+
* @param {Transaction} transaction the transaction to sign
|
|
225
|
+
* @param {number} sighashType the type of the hash
|
|
226
|
+
* @param {number} inputNumber the input index for the signature
|
|
227
|
+
* @param {Script} subscript the script that will be signed
|
|
228
|
+
* @param {satoshisBN} input's amount (for ForkId signatures)
|
|
229
|
+
*
|
|
230
|
+
*/
|
|
231
|
+
var sighash = function sighash (transaction, sighashType, inputNumber, subscript, satoshisBN, flags) {
|
|
232
|
+
var preimage = sighashPreimage(transaction, sighashType, inputNumber, subscript, satoshisBN, flags)
|
|
233
|
+
if (preimage.compare(SIGHASH_SINGLE_BUG) === 0) return preimage
|
|
234
|
+
var ret = Hash.sha256sha256(preimage)
|
|
235
|
+
ret = new BufferReader(ret).readReverse()
|
|
236
|
+
return ret
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create a signature
|
|
241
|
+
*
|
|
242
|
+
* @name Signing.sign
|
|
243
|
+
* @param {Transaction} transaction
|
|
244
|
+
* @param {PrivateKey} privateKey
|
|
245
|
+
* @param {number} sighash
|
|
246
|
+
* @param {number} inputIndex
|
|
247
|
+
* @param {Script} subscript
|
|
248
|
+
* @param {satoshisBN} input's amount
|
|
249
|
+
* @return {Signature}
|
|
250
|
+
*/
|
|
251
|
+
function sign (transaction, privateKey, sighashType, inputIndex, subscript, satoshisBN, flags) {
|
|
252
|
+
var hashbuf = sighash(transaction, sighashType, inputIndex, subscript, satoshisBN, flags)
|
|
253
|
+
|
|
254
|
+
var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({
|
|
255
|
+
nhashtype: sighashType
|
|
256
|
+
})
|
|
257
|
+
return sig
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Verify a signature
|
|
262
|
+
*
|
|
263
|
+
* @name Signing.verify
|
|
264
|
+
* @param {Transaction} transaction
|
|
265
|
+
* @param {Signature} signature
|
|
266
|
+
* @param {PublicKey} publicKey
|
|
267
|
+
* @param {number} inputIndex
|
|
268
|
+
* @param {Script} subscript
|
|
269
|
+
* @param {satoshisBN} input's amount
|
|
270
|
+
* @param {flags} verification flags
|
|
271
|
+
* @return {boolean}
|
|
272
|
+
*/
|
|
273
|
+
function verify (transaction, signature, publicKey, inputIndex, subscript, satoshisBN, flags) {
|
|
274
|
+
$.checkArgument(!_.isUndefined(transaction))
|
|
275
|
+
$.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype))
|
|
276
|
+
var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript, satoshisBN, flags)
|
|
277
|
+
return ECDSA.verify(hashbuf, signature, publicKey, 'little')
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @namespace Signing
|
|
282
|
+
*/
|
|
283
|
+
module.exports = {
|
|
284
|
+
sighashPreimage: sighashPreimage,
|
|
285
|
+
sighash: sighash,
|
|
286
|
+
sign: sign,
|
|
287
|
+
verify: verify
|
|
288
|
+
}
|