Browse Source

Fixed script, script number and signature

fixTypes
junderw 6 years ago
parent
commit
3b77caa4f1
No known key found for this signature in database GPG Key ID: B256185D3A971908
  1. 74
      src/script.ts
  2. 10
      src/script_number.ts
  3. 19
      src/script_signature.ts

74
src/script.ts

@ -10,37 +10,49 @@ const OPS = require('bitcoin-ops')
const REVERSE_OPS = require('bitcoin-ops/map') const REVERSE_OPS = require('bitcoin-ops/map')
const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1
function isOPInt (value) { function isOPInt (value:number): boolean {
return types.Number(value) && return types.Number(value) &&
((value === OPS.OP_0) || ((value === OPS.OP_0) ||
(value >= OPS.OP_1 && value <= OPS.OP_16) || (value >= OPS.OP_1 && value <= OPS.OP_16) ||
(value === OPS.OP_1NEGATE)) (value === OPS.OP_1NEGATE))
} }
function isPushOnlyChunk (value) { function isPushOnlyChunk (value: number | Buffer): boolean {
return types.Buffer(value) || isOPInt(value) return types.Buffer(value) || isOPInt(<number>value)
} }
function isPushOnly (value) { export function isPushOnly (value: Array<number | Buffer>) {
return types.Array(value) && value.every(isPushOnlyChunk) return types.Array(value) && value.every(isPushOnlyChunk)
} }
function asMinimalOP (buffer) { function asMinimalOP (buffer: Buffer): number | void {
if (buffer.length === 0) return OPS.OP_0 if (buffer.length === 0) return OPS.OP_0
if (buffer.length !== 1) return if (buffer.length !== 1) return
if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0] if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]
if (buffer[0] === 0x81) return OPS.OP_1NEGATE if (buffer[0] === 0x81) return OPS.OP_1NEGATE
} }
function compile (chunks) { function chunksIsBuffer(buf: Buffer | Array<number | Buffer>): buf is Buffer {
return Buffer.isBuffer(buf)
}
function chunksIsArray(buf: Buffer | Array<number | Buffer>): buf is Array<number | Buffer> {
return types.Array(buf)
}
function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer {
return Buffer.isBuffer(buf)
}
export function compile (chunks: Buffer | Array<number | Buffer>): Buffer {
// TODO: remove me // TODO: remove me
if (Buffer.isBuffer(chunks)) return chunks if (chunksIsBuffer(chunks)) return chunks
typeforce(types.Array, chunks) typeforce(types.Array, chunks)
const bufferSize = chunks.reduce(function (accum, chunk) { const bufferSize = chunks.reduce(function (accum: number, chunk) {
// data chunk // data chunk
if (Buffer.isBuffer(chunk)) { if (singleChunkIsBuffer(chunk)) {
// adhere to BIP62.3, minimal push policy // adhere to BIP62.3, minimal push policy
if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) {
return accum + 1 return accum + 1
@ -58,7 +70,7 @@ function compile (chunks) {
chunks.forEach(function (chunk) { chunks.forEach(function (chunk) {
// data chunk // data chunk
if (Buffer.isBuffer(chunk)) { if (singleChunkIsBuffer(chunk)) {
// adhere to BIP62.3, minimal push policy // adhere to BIP62.3, minimal push policy
const opcode = asMinimalOP(chunk) const opcode = asMinimalOP(chunk)
if (opcode !== undefined) { if (opcode !== undefined) {
@ -82,9 +94,9 @@ function compile (chunks) {
return buffer return buffer
} }
function decompile (buffer) { export function decompile (buffer: Buffer | Array<number | Buffer>): Array<number | Buffer> {
// TODO: remove me // TODO: remove me
if (types.Array(buffer)) return buffer if (chunksIsArray(buffer)) return buffer
typeforce(types.Buffer, buffer) typeforce(types.Buffer, buffer)
@ -127,17 +139,17 @@ function decompile (buffer) {
return chunks return chunks
} }
function toASM (chunks) { export function toASM (chunks: Buffer | Array<number | Buffer>): string {
if (Buffer.isBuffer(chunks)) { if (chunksIsBuffer(chunks)) {
chunks = decompile(chunks) chunks = decompile(chunks)
} }
return chunks.map(function (chunk) { return chunks.map(function (chunk) {
// data? // data?
if (Buffer.isBuffer(chunk)) { if (singleChunkIsBuffer(chunk)) {
const op = asMinimalOP(chunk) const op = asMinimalOP(chunk)
if (op === undefined) return chunk.toString('hex') if (op === undefined) return chunk.toString('hex')
chunk = op chunk = <number>op
} }
// opcode! // opcode!
@ -145,7 +157,7 @@ function toASM (chunks) {
}).join(' ') }).join(' ')
} }
function fromASM (asm) { export function fromASM (asm: string): Buffer {
typeforce(types.String, asm) typeforce(types.String, asm)
return compile(asm.split(' ').map(function (chunkStr) { return compile(asm.split(' ').map(function (chunkStr) {
@ -158,49 +170,35 @@ function fromASM (asm) {
})) }))
} }
function toStack (chunks) { export function toStack (chunks: Buffer | Array<number | Buffer>): Array<Buffer> {
chunks = decompile(chunks) chunks = decompile(chunks)
typeforce(isPushOnly, chunks) typeforce(isPushOnly, chunks)
return chunks.map(function (op) { return chunks.map(function (op) {
if (Buffer.isBuffer(op)) return op if (singleChunkIsBuffer(op)) return op
if (op === OPS.OP_0) return Buffer.allocUnsafe(0) if (op === OPS.OP_0) return Buffer.allocUnsafe(0)
return scriptNumber.encode(op - OP_INT_BASE) return scriptNumber.encode(op - OP_INT_BASE)
}) })
} }
function isCanonicalPubKey (buffer) { export function isCanonicalPubKey (buffer: Buffer): boolean {
return ecc.isPoint(buffer) return ecc.isPoint(buffer)
} }
function isDefinedHashType (hashType) { export function isDefinedHashType (hashType: number): boolean {
const hashTypeMod = hashType & ~0x80 const hashTypeMod = hashType & ~0x80
// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
return hashTypeMod > 0x00 && hashTypeMod < 0x04 return hashTypeMod > 0x00 && hashTypeMod < 0x04
} }
function isCanonicalScriptSignature (buffer) { export function isCanonicalScriptSignature (buffer: Buffer): boolean {
if (!Buffer.isBuffer(buffer)) return false if (!Buffer.isBuffer(buffer)) return false
if (!isDefinedHashType(buffer[buffer.length - 1])) return false if (!isDefinedHashType(buffer[buffer.length - 1])) return false
return bip66.check(buffer.slice(0, -1)) return bip66.check(buffer.slice(0, -1))
} }
module.exports = { export const number = require('./script_number')
compile: compile, export const signature = require('./script_signature')
decompile: decompile,
fromASM: fromASM,
toASM: toASM,
toStack: toStack,
number: require('./script_number'),
signature: require('./script_signature'),
isCanonicalPubKey: isCanonicalPubKey,
isCanonicalScriptSignature: isCanonicalScriptSignature,
isPushOnly: isPushOnly,
isDefinedHashType: isDefinedHashType
}
export {}

10
src/script_number.ts

@ -1,6 +1,6 @@
const Buffer = require('safe-buffer').Buffer const Buffer = require('safe-buffer').Buffer
function decode (buffer, maxLength, minimal) { export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): number {
maxLength = maxLength || 4 maxLength = maxLength || 4
minimal = minimal === undefined ? true : minimal minimal = minimal === undefined ? true : minimal
@ -41,7 +41,7 @@ function scriptNumSize (i) {
: 0 : 0
} }
function encode (number) { export function encode (number: number): Buffer {
let value = Math.abs(number) let value = Math.abs(number)
const size = scriptNumSize(value) const size = scriptNumSize(value)
const buffer = Buffer.allocUnsafe(size) const buffer = Buffer.allocUnsafe(size)
@ -60,9 +60,3 @@ function encode (number) {
return buffer return buffer
} }
module.exports = {
decode: decode,
encode: encode
}
export {}

19
src/script_signature.ts

@ -4,7 +4,7 @@ const typeforce = require('typeforce')
const types = require('./types') const types = require('./types')
const ZERO = Buffer.alloc(1, 0) const ZERO = Buffer.alloc(1, 0)
function toDER (x) { function toDER (x: Buffer): Buffer {
let i = 0 let i = 0
while (x[i] === 0) ++i while (x[i] === 0) ++i
if (i === x.length) return ZERO if (i === x.length) return ZERO
@ -13,7 +13,7 @@ function toDER (x) {
return x return x
} }
function fromDER (x) { function fromDER (x: Buffer): Buffer {
if (x[0] === 0x00) x = x.slice(1) if (x[0] === 0x00) x = x.slice(1)
const buffer = Buffer.alloc(32, 0) const buffer = Buffer.alloc(32, 0)
const bstart = Math.max(0, 32 - x.length) const bstart = Math.max(0, 32 - x.length)
@ -21,8 +21,13 @@ function fromDER (x) {
return buffer return buffer
} }
interface ScriptSignature {
signature: Buffer
hashType: number
}
// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
function decode (buffer) { export function decode (buffer: Buffer): ScriptSignature {
const hashType = buffer.readUInt8(buffer.length - 1) const hashType = buffer.readUInt8(buffer.length - 1)
const hashTypeMod = hashType & ~0x80 const hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
@ -37,7 +42,7 @@ function decode (buffer) {
} }
} }
function encode (signature, hashType) { export function encode (signature: Buffer, hashType: number): Buffer {
typeforce({ typeforce({
signature: types.BufferN(64), signature: types.BufferN(64),
hashType: types.UInt8 hashType: types.UInt8
@ -57,9 +62,3 @@ function encode (signature, hashType) {
hashTypeBuffer hashTypeBuffer
]) ])
} }
module.exports = {
decode: decode,
encode: encode
}
export {}

Loading…
Cancel
Save