UNPKG

5.75 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3exports.signature =
4 exports.number =
5 exports.isCanonicalScriptSignature =
6 exports.isDefinedHashType =
7 exports.isCanonicalPubKey =
8 exports.toStack =
9 exports.fromASM =
10 exports.toASM =
11 exports.decompile =
12 exports.compile =
13 exports.countNonPushOnlyOPs =
14 exports.isPushOnly =
15 exports.OPS =
16 void 0;
17const bip66 = require('./bip66');
18const ops_1 = require('./ops');
19Object.defineProperty(exports, 'OPS', {
20 enumerable: true,
21 get: function () {
22 return ops_1.OPS;
23 },
24});
25const pushdata = require('./push_data');
26const scriptNumber = require('./script_number');
27const scriptSignature = require('./script_signature');
28const types = require('./types');
29const { typeforce } = types;
30const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1
31function isOPInt(value) {
32 return (
33 types.Number(value) &&
34 (value === ops_1.OPS.OP_0 ||
35 (value >= ops_1.OPS.OP_1 && value <= ops_1.OPS.OP_16) ||
36 value === ops_1.OPS.OP_1NEGATE)
37 );
38}
39function isPushOnlyChunk(value) {
40 return types.Buffer(value) || isOPInt(value);
41}
42function isPushOnly(value) {
43 return types.Array(value) && value.every(isPushOnlyChunk);
44}
45exports.isPushOnly = isPushOnly;
46function countNonPushOnlyOPs(value) {
47 return value.length - value.filter(isPushOnlyChunk).length;
48}
49exports.countNonPushOnlyOPs = countNonPushOnlyOPs;
50function asMinimalOP(buffer) {
51 if (buffer.length === 0) return ops_1.OPS.OP_0;
52 if (buffer.length !== 1) return;
53 if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
54 if (buffer[0] === 0x81) return ops_1.OPS.OP_1NEGATE;
55}
56function chunksIsBuffer(buf) {
57 return Buffer.isBuffer(buf);
58}
59function chunksIsArray(buf) {
60 return types.Array(buf);
61}
62function singleChunkIsBuffer(buf) {
63 return Buffer.isBuffer(buf);
64}
65function compile(chunks) {
66 // TODO: remove me
67 if (chunksIsBuffer(chunks)) return chunks;
68 typeforce(types.Array, chunks);
69 const bufferSize = chunks.reduce((accum, chunk) => {
70 // data chunk
71 if (singleChunkIsBuffer(chunk)) {
72 // adhere to BIP62.3, minimal push policy
73 if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) {
74 return accum + 1;
75 }
76 return accum + pushdata.encodingLength(chunk.length) + chunk.length;
77 }
78 // opcode
79 return accum + 1;
80 }, 0.0);
81 const buffer = Buffer.allocUnsafe(bufferSize);
82 let offset = 0;
83 chunks.forEach(chunk => {
84 // data chunk
85 if (singleChunkIsBuffer(chunk)) {
86 // adhere to BIP62.3, minimal push policy
87 const opcode = asMinimalOP(chunk);
88 if (opcode !== undefined) {
89 buffer.writeUInt8(opcode, offset);
90 offset += 1;
91 return;
92 }
93 offset += pushdata.encode(buffer, chunk.length, offset);
94 chunk.copy(buffer, offset);
95 offset += chunk.length;
96 // opcode
97 } else {
98 buffer.writeUInt8(chunk, offset);
99 offset += 1;
100 }
101 });
102 if (offset !== buffer.length) throw new Error('Could not decode chunks');
103 return buffer;
104}
105exports.compile = compile;
106function decompile(buffer) {
107 // TODO: remove me
108 if (chunksIsArray(buffer)) return buffer;
109 typeforce(types.Buffer, buffer);
110 const chunks = [];
111 let i = 0;
112 while (i < buffer.length) {
113 const opcode = buffer[i];
114 // data chunk
115 if (opcode > ops_1.OPS.OP_0 && opcode <= ops_1.OPS.OP_PUSHDATA4) {
116 const d = pushdata.decode(buffer, i);
117 // did reading a pushDataInt fail?
118 if (d === null) return null;
119 i += d.size;
120 // attempt to read too much data?
121 if (i + d.number > buffer.length) return null;
122 const data = buffer.slice(i, i + d.number);
123 i += d.number;
124 // decompile minimally
125 const op = asMinimalOP(data);
126 if (op !== undefined) {
127 chunks.push(op);
128 } else {
129 chunks.push(data);
130 }
131 // opcode
132 } else {
133 chunks.push(opcode);
134 i += 1;
135 }
136 }
137 return chunks;
138}
139exports.decompile = decompile;
140function toASM(chunks) {
141 if (chunksIsBuffer(chunks)) {
142 chunks = decompile(chunks);
143 }
144 return chunks
145 .map(chunk => {
146 // data?
147 if (singleChunkIsBuffer(chunk)) {
148 const op = asMinimalOP(chunk);
149 if (op === undefined) return chunk.toString('hex');
150 chunk = op;
151 }
152 // opcode!
153 return ops_1.REVERSE_OPS[chunk];
154 })
155 .join(' ');
156}
157exports.toASM = toASM;
158function fromASM(asm) {
159 typeforce(types.String, asm);
160 return compile(
161 asm.split(' ').map(chunkStr => {
162 // opcode?
163 if (ops_1.OPS[chunkStr] !== undefined) return ops_1.OPS[chunkStr];
164 typeforce(types.Hex, chunkStr);
165 // data!
166 return Buffer.from(chunkStr, 'hex');
167 }),
168 );
169}
170exports.fromASM = fromASM;
171function toStack(chunks) {
172 chunks = decompile(chunks);
173 typeforce(isPushOnly, chunks);
174 return chunks.map(op => {
175 if (singleChunkIsBuffer(op)) return op;
176 if (op === ops_1.OPS.OP_0) return Buffer.allocUnsafe(0);
177 return scriptNumber.encode(op - OP_INT_BASE);
178 });
179}
180exports.toStack = toStack;
181function isCanonicalPubKey(buffer) {
182 return types.isPoint(buffer);
183}
184exports.isCanonicalPubKey = isCanonicalPubKey;
185function isDefinedHashType(hashType) {
186 const hashTypeMod = hashType & ~0x80;
187 // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
188 return hashTypeMod > 0x00 && hashTypeMod < 0x04;
189}
190exports.isDefinedHashType = isDefinedHashType;
191function isCanonicalScriptSignature(buffer) {
192 if (!Buffer.isBuffer(buffer)) return false;
193 if (!isDefinedHashType(buffer[buffer.length - 1])) return false;
194 return bip66.check(buffer.slice(0, -1));
195}
196exports.isCanonicalScriptSignature = isCanonicalScriptSignature;
197exports.number = scriptNumber;
198exports.signature = scriptSignature;