1 | 'use strict';
|
2 |
|
3 |
|
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 _ = require('lodash');
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | var sighash = function sighash(transaction, sighashType, inputNumber, scriptCode, satoshisBuffer) {
|
29 |
|
30 |
|
31 | var hashPrevouts;
|
32 | var hashSequence;
|
33 | var hashOutputs;
|
34 |
|
35 | if (!(sighashType & Signature.SIGHASH_ANYONECANPAY)) {
|
36 | var buffers = [];
|
37 | for (var n = 0; n < transaction.inputs.length; n++) {
|
38 | var input = transaction.inputs[n];
|
39 | var prevTxIdBuffer = new BufferReader(input.prevTxId).readReverse();
|
40 | buffers.push(prevTxIdBuffer);
|
41 | var outputIndexBuffer = Buffer.alloc(4);
|
42 | outputIndexBuffer.writeUInt32LE(input.outputIndex, 0);
|
43 | buffers.push(outputIndexBuffer);
|
44 | }
|
45 | hashPrevouts = Hash.sha256sha256(Buffer.concat(buffers));
|
46 | }
|
47 |
|
48 | if (!(sighashType & Signature.SIGHASH_ANYONECANPAY) &&
|
49 | (sighashType & 0x1f) !== Signature.SIGHASH_SINGLE && (sighashType & 0x1f) !== Signature.SIGHASH_NONE) {
|
50 |
|
51 | var sequenceBuffers = [];
|
52 | for (var m = 0; m < transaction.inputs.length; m++) {
|
53 | var sequenceBuffer = Buffer.alloc(4);
|
54 | sequenceBuffer.writeUInt32LE(transaction.inputs[m].sequenceNumber, 0);
|
55 | sequenceBuffers.push(sequenceBuffer);
|
56 | }
|
57 | hashSequence = Hash.sha256sha256(Buffer.concat(sequenceBuffers));
|
58 | }
|
59 |
|
60 | var outputWriter = new BufferWriter();
|
61 | if ((sighashType & 0x1f) !== Signature.SIGHASH_SINGLE && (sighashType & 0x1f) !== Signature.SIGHASH_NONE) {
|
62 | for (var p = 0; p < transaction.outputs.length; p++) {
|
63 | transaction.outputs[p].toBufferWriter(outputWriter);
|
64 | }
|
65 | hashOutputs = Hash.sha256sha256(outputWriter.toBuffer());
|
66 | } else if ((sighashType & 0x1f) === Signature.SIGHASH_SINGLE && inputNumber < transaction.outputs.length) {
|
67 | transaction.outputs[inputNumber].toBufferWriter(outputWriter);
|
68 | hashOutputs = Hash.sha256sha256(outputWriter.toBuffer());
|
69 | }
|
70 |
|
71 |
|
72 | var writer = new BufferWriter();
|
73 | writer.writeUInt32LE(transaction.version);
|
74 |
|
75 |
|
76 | writer.write(hashPrevouts);
|
77 | writer.write(hashSequence);
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | var outpointId = new BufferReader(transaction.inputs[inputNumber].prevTxId).readReverse();
|
83 | writer.write(outpointId);
|
84 | writer.writeUInt32LE(transaction.inputs[inputNumber].outputIndex);
|
85 |
|
86 | writer.write(scriptCode);
|
87 |
|
88 | writer.write(satoshisBuffer);
|
89 |
|
90 | writer.writeUInt32LE(transaction.inputs[inputNumber].sequenceNumber);
|
91 |
|
92 |
|
93 | writer.write(hashOutputs);
|
94 |
|
95 |
|
96 | writer.writeUInt32LE(transaction.nLockTime);
|
97 |
|
98 |
|
99 | writer.writeInt32LE(sighashType);
|
100 |
|
101 | return Hash.sha256sha256(writer.toBuffer());
|
102 |
|
103 | };
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | function sign(transaction, privateKey, sighashType, inputIndex, scriptCode, satoshisBuffer, signingMethod) {
|
118 | signingMethod = signingMethod || 'ecdsa';
|
119 | var sig;
|
120 |
|
121 | if (signingMethod === 'ecdsa') {
|
122 | let hashbuf = sighash(transaction, sighashType, inputIndex, scriptCode, satoshisBuffer);
|
123 | sig = ECDSA.sign(hashbuf, privateKey).set({
|
124 | nhashtype: sighashType
|
125 | });
|
126 | return sig;
|
127 | }
|
128 | throw new Error("signingMethod not supported ", signingMethod);
|
129 | }
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 | function verify(transaction, signature, publicKey, inputIndex, scriptCode, satoshisBuffer, signingMethod) {
|
144 | $.checkArgument(!_.isUndefined(transaction));
|
145 | $.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype));
|
146 | signingMethod = signingMethod || 'ecdsa';
|
147 |
|
148 | if (signingMethod === 'ecdsa') {
|
149 | let hashbuf = sighash(transaction, signature.nhashtype, inputIndex, scriptCode, satoshisBuffer);
|
150 | return ECDSA.verify(hashbuf, signature, publicKey);
|
151 | }
|
152 | throw new Error("signingMethod not supported ", signingMethod);
|
153 | }
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | module.exports = {
|
159 | sighash: sighash,
|
160 | sign: sign,
|
161 | verify: verify
|
162 | };
|