<commit_before>var assert = require('assert')
var enforceType = require('./types')
var ops = require('./opcodes')

var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var ECSignature = require('./ecsignature')
var Script = require('./script')

function isCanonicalPubKey(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e

    return false
  }

  return true
}

function isCanonicalSignature(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ECSignature.parseScriptSignature(buffer)
  } catch(e) {
    if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) throw e

    return false
  }

  return true
}

function isPubKeyHashInput() {
  return this.chunks.length === 2 &&
    isCanonicalSignature(this.chunks[0]) &&
    isCanonicalPubKey(this.chunks[1])
}

function isPubKeyHashOutput() {
  return this.chunks.length === 5 &&
    this.chunks[0] === ops.OP_DUP &&
    this.chunks[1] === ops.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[2]) &&
    this.chunks[2].length === 20 &&
    this.chunks[3] === ops.OP_EQUALVERIFY &&
    this.chunks[4] === ops.OP_CHECKSIG
}

function isPubKeyInput() {
  return this.chunks.length === 1 &&
    isCanonicalSignature(this.chunks[0])
}

function isPubKeyOutput() {
  return this.chunks.length === 2 &&
    isCanonicalPubKey(this.chunks[0]) &&
    this.chunks[1] === ops.OP_CHECKSIG
}

function isScriptHashInput() {
  if (this.chunks.length < 2) return false
  var lastChunk = this.chunks[this.chunks.length - 1]

  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSig = Script.fromChunks(this.chunks.slice(0, -1))
  var scriptPubKey = Script.fromBuffer(lastChunk)

  return classifyInput(scriptSig) === classifyOutput(scriptPubKey)
}

function isScriptHashOutput() {
  return this.chunks.length === 3 &&
    this.chunks[0] === ops.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[1]) &&
    this.chunks[1].length === 20 &&
    this.chunks[2] === ops.OP_EQUAL
}

function isMultisigInput() {
  return this.chunks[0] === ops.OP_0 &&
    this.chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput() {
  if (this.chunks < 4) return false
  if (this.chunks[this.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false

  var mOp = this.chunks[0]
  if (mOp === ops.OP_0) return false
  if (mOp < ops.OP_1) return false
  if (mOp > ops.OP_16) return false

  var nOp = this.chunks[this.chunks.length - 2]
  if (nOp === ops.OP_0) return false
  if (nOp < ops.OP_1) return false
  if (nOp > ops.OP_16) return false

  var m = mOp - (ops.OP_1 - 1)
  var n = nOp - (ops.OP_1 - 1)
  if (n < m) return false

  var pubKeys = this.chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNulldataOutput() {
  return this.chunks[0] === ops.OP_RETURN
}

function classifyOutput(script) {
  enforceType(Script, script)

  if (isPubKeyHashOutput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput.call(script)) {
    return 'scripthash'
  } else if (isMultisigOutput.call(script)) {
    return 'multisig'
  } else if (isPubKeyOutput.call(script)) {
    return 'pubkey'
  } else if (isNulldataOutput.call(script)) {
    return 'nulldata'
  } else {
    return 'nonstandard'
  }
}

function classifyInput(script) {
  enforceType(Script, script)

  if (isPubKeyHashInput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashInput.call(script)) {
    return 'scripthash'
  } else if (isMultisigInput.call(script)) {
    return 'multisig'
  } else if (isPubKeyInput.call(script)) {
    return 'pubkey'
  } else {
    return 'nonstandard'
  }
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) {
  return Script.fromChunks([
    pubKey.toBuffer(),
    ops.OP_CHECKSIG
  ])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
  enforceType('Buffer', hash)

  return Script.fromChunks([
    ops.OP_DUP,
    ops.OP_HASH160,
    hash,
    ops.OP_EQUALVERIFY,
    ops.OP_CHECKSIG
  ])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
  enforceType('Buffer', hash)

  return Script.fromChunks([
    ops.OP_HASH160,
    hash,
    ops.OP_EQUAL
  ])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
  enforceType('Array', pubKeys)

  assert(pubKeys.length >= m, 'Not enough pubKeys provided')

  var pubKeyBuffers = pubKeys.map(function(pubKey) {
    return pubKey.toBuffer()
  })
  var n = pubKeys.length

  return Script.fromChunks([].concat(
    (ops.OP_1 - 1) + m,
    pubKeyBuffers,
    (ops.OP_1 - 1) + n,
    ops.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput(signature) {
  enforceType('Buffer', signature)

  return Script.fromChunks([signature])
}

// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
  enforceType('Buffer', signature)

  return Script.fromChunks([signature, pubKey.toBuffer()])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput(scriptSig, scriptPubKey) {
  return Script.fromChunks([].concat(
    scriptSig.chunks,
    scriptPubKey.toBuffer()
  ))
}

// OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) {
  if (scriptPubKey) {
    assert(isMultisigOutput.call(scriptPubKey))

    var mOp = scriptPubKey.chunks[0]
    var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
    var m = mOp - (ops.OP_1 - 1)
    var n = nOp - (ops.OP_1 - 1)

    assert(signatures.length >= m, 'Not enough signatures provided')
    assert(signatures.length <= n, 'Too many signatures provided')
  }

  return Script.fromChunks([].concat(ops.OP_0, signatures))
}

module.exports = {
  classifyInput: classifyInput,
  classifyOutput: classifyOutput,
  multisigInput: multisigInput,<commit_msg>scripts: avoid unnecessary this context<commit_after>var assert = require('assert')
var enforceType = require('./types')
var ops = require('./opcodes')

var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var ECSignature = require('./ecsignature')
var Script = require('./script')

function isCanonicalPubKey(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e

    return false
  }

  return true
}

function isCanonicalSignature(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ECSignature.parseScriptSignature(buffer)
  } catch(e) {
    if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) throw e

    return false
  }

  return true
}

function isPubKeyHashInput(script) {
  return script.chunks.length === 2 &&
    isCanonicalSignature(script.chunks[0]) &&
    isCanonicalPubKey(script.chunks[1])
}

function isPubKeyHashOutput(script) {
  return script.chunks.length === 5 &&
    script.chunks[0] === ops.OP_DUP &&
    script.chunks[1] === ops.OP_HASH160 &&
    Buffer.isBuffer(script.chunks[2]) &&
    script.chunks[2].length === 20 &&
    script.chunks[3] === ops.OP_EQUALVERIFY &&
    script.chunks[4] === ops.OP_CHECKSIG
}

function isPubKeyInput(script) {
  return script.chunks.length === 1 &&
    isCanonicalSignature(script.chunks[0])
}

function isPubKeyOutput(script) {
  return script.chunks.length === 2 &&
    isCanonicalPubKey(script.chunks[0]) &&
    script.chunks[1] === ops.OP_CHECKSIG
}

function isScriptHashInput(script) {
  if (script.chunks.length < 2) return false
  var lastChunk = script.chunks[script.chunks.length - 1]

  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSig = Script.fromChunks(script.chunks.slice(0, -1))
  var scriptPubKey = Script.fromBuffer(lastChunk)

  return classifyInput(scriptSig) === classifyOutput(scriptPubKey)
}

function isScriptHashOutput(script) {
  return script.chunks.length === 3 &&
    script.chunks[0] === ops.OP_HASH160 &&
    Buffer.isBuffer(script.chunks[1]) &&
    script.chunks[1].length === 20 &&
    script.chunks[2] === ops.OP_EQUAL
}

function isMultisigInput(script) {
  return script.chunks[0] === ops.OP_0 &&
    script.chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput(script) {
  if (script.chunks < 4) return false
  if (script.chunks[script.chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false

  var mOp = script.chunks[0]
  if (mOp === ops.OP_0) return false
  if (mOp < ops.OP_1) return false
  if (mOp > ops.OP_16) return false

  var nOp = script.chunks[script.chunks.length - 2]
  if (nOp === ops.OP_0) return false
  if (nOp < ops.OP_1) return false
  if (nOp > ops.OP_16) return false

  var m = mOp - (ops.OP_1 - 1)
  var n = nOp - (ops.OP_1 - 1)
  if (n < m) return false

  var pubKeys = script.chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNulldataOutput(script) {
  return script.chunks[0] === ops.OP_RETURN
}

function classifyOutput(script) {
  enforceType(Script, script)

  if (isPubKeyHashOutput(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput(script)) {
    return 'scripthash'
  } else if (isMultisigOutput(script)) {
    return 'multisig'
  } else if (isPubKeyOutput(script)) {
    return 'pubkey'
  } else if (isNulldataOutput(script)) {
    return 'nulldata'
  } else {
    return 'nonstandard'
  }
}

function classifyInput(script) {
  enforceType(Script, script)

  if (isPubKeyHashInput(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashInput(script)) {
    return 'scripthash'
  } else if (isMultisigInput(script)) {
    return 'multisig'
  } else if (isPubKeyInput(script)) {
    return 'pubkey'
  } else {
    return 'nonstandard'
  }
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) {
  return Script.fromChunks([
    pubKey.toBuffer(),
    ops.OP_CHECKSIG
  ])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
  enforceType('Buffer', hash)

  return Script.fromChunks([
    ops.OP_DUP,
    ops.OP_HASH160,
    hash,
    ops.OP_EQUALVERIFY,
    ops.OP_CHECKSIG
  ])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
  enforceType('Buffer', hash)

  return Script.fromChunks([
    ops.OP_HASH160,
    hash,
    ops.OP_EQUAL
  ])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
  enforceType('Array', pubKeys)

  assert(pubKeys.length >= m, 'Not enough pubKeys provided')

  var pubKeyBuffers = pubKeys.map(function(pubKey) {
    return pubKey.toBuffer()
  })
  var n = pubKeys.length

  return Script.fromChunks([].concat(
    (ops.OP_1 - 1) + m,
    pubKeyBuffers,
    (ops.OP_1 - 1) + n,
    ops.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput(signature) {
  enforceType('Buffer', signature)

  return Script.fromChunks([signature])
}

// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
  enforceType('Buffer', signature)

  return Script.fromChunks([signature, pubKey.toBuffer()])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput(scriptSig, scriptPubKey) {
  return Script.fromChunks([].concat(
    scriptSig.chunks,
    scriptPubKey.toBuffer()
  ))
}

// OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) {
  if (scriptPubKey) {
    assert(isMultisigOutput(scriptPubKey))

    var mOp = scriptPubKey.chunks[0]
    var nOp = scriptPubKey.chunks[scriptPubKey.chunks.length - 2]
    var m = mOp - (ops.OP_1 - 1)
    var n = nOp - (ops.OP_1 - 1)

    assert(signatures.length >= m, 'Not enough signatures provided')
    assert(signatures.length <= n, 'Too many signatures provided')
  }

  return Script.fromChunks([].concat(ops.OP_0, signatures))
}

module.exports = {
  classifyInput: classifyInput,
  classifyOutput: classifyOutput,
  multisigInput: multisigInput,
{'fraction_non_alphanumeric': 0.13390105433901053, 'fraction_numerical': 0.013625304136253041, 'mean_word_length': 3.9304278288684524, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4175977', 'n_tokens_mistral': 4464, 'n_tokens_neox': 4317, 'n_words': 905}