<commit_before>'use strict'
const crypto = require('crypto')
const asn1 = require('asn1.js')

const ec_pem_api = {
  __proto__: Object.getPrototypeOf(crypto.createECDH('prime256v1')),
  encodePrivateKey(enc) { return encodePrivateKey(this, enc) },
  encodePublicKey(enc) { return encodePublicKey(this, enc) },
  sign(algorithm, ...optionalArgs) { return sign(this, algorithm, ...optionalArgs) },
  verify(algorithm, ...optionalArgs) { return verify(this, algorithm, ...optionalArgs) },
  clone(kind) { return clone(this, kind) },
  clonePublic() { return clonePublic(this) },
  clonePrivate() { return clonePrivate(this) },
  toPublicJSON(format) { return toPublicJSON(this, format) },
  toPrivateJSON() { return toPrivateJSON(this) },
  toPublicBase64(extra, format) { return toPublicBase64(this, extra, format) },
  toPrivateBase64(extra) { return toPrivateBase64(this, extra) },
  toPublicBuffer(format) { return toPublicBuffer(this, format) },
  toPrivateBuffer() { return toPrivateBuffer(this) },
}

const curveByKeySize = {
  '49': [ 'prime192v1' ],
  '49,24': [ 'prime192v1' ],
  '65': [ 'prime256v1' ],
  '65,32': [ 'prime256v1' ],
  '43': [ 'sect163k1', 'sect163r2' ],
  '43,21': [ 'sect163k1', 'sect163r2' ],
  '43,20': [ 'sect163k1', 'sect163r2' ],
  '57': [ 'secp224r1' ],
  '57,28': [ 'secp224r1' ],
  '61': [ 'sect233k1', 'sect233r1' ],
  '61,29': [ 'sect233k1', 'sect233r1' ],
  '61,28': [ 'sect233r1' ],
  '73': [ 'sect283k1', 'sect283r1' ],
  '73,36': [ 'sect283k1', 'sect283r1' ],
  '73,35': [ 'sect283k1', 'sect283r1' ],
  '97': [ 'secp384r1' ],
  '97,48': [ 'secp384r1' ],
  '105': [ 'sect409k1', 'sect409r1' ],
  '105,51': [ 'sect409k1', 'sect409r1' ],
  '133': [ 'secp521r1' ],
  '133,66': [ 'secp521r1' ],
  '133,65': [ 'secp521r1' ],
  '145': [ 'sect571k1', 'sect571r1' ],
  '145,71': [ 'sect571k1', 'sect571r1' ],
  '145,72': [ 'sect571k1', 'sect571r1' ] }

function ec_pem(ecdh, curve) {
  if ('string' === typeof ecdh && undefined === curve)
    curve = ecdh, ecdh = null;
  else if (!curve && ecdh)
    curve = ecdh.curve || inferCurve(ecdh, true)

  if (!curve)
    throw new Error("EC curve must be specified for PEM encoding support")

  if (null == ecdh)
    ecdh = crypto.createECDH(curve)

  Object.setPrototypeOf(ecdh, ec_pem_api)
  ecdh.curve = curve
  return ecdh
}

exports = module.exports = Object.assign(ec_pem, {
  ec_pem, ec_pem_api, generate, load, decode, sign, verify,
  loadPrivateKey, decodePrivateKey, encodePrivateKey,
  loadPublicKey, decodePublicKey, encodePublicKey,
  clonePrivate, clonePublic, clone,
  asUrlSafeBase64,
  toPrivateJSON, toPublicJSON, fromJSON,
  toPrivateBase64, toPublicBase64, fromBase64,
  toPrivateBuffer, toPublicBuffer, fromBuffer,
  inferCurve, inferCurveByLengths,
  pemDecodeRaw, pemEncodeRaw })


function inferCurve(ecdh, exactlyOne) {
  const keyLengths = [ecdh.getPublicKey().length]
  try { keyLengths.push(ecdh.getPrivateKey().length) }
  catch (err) {}
  return inferCurveByLengths(keyLengths, exactlyOne) }
function inferCurveByLengths(keyLengths, exactlyOne) {
  if (Number.isInteger(keyLengths))
    keyLengths = [keyLengths,]
  const ans = curveByKeySize[keyLengths]
  if (!exactlyOne) return ans
  return (ans.length === 1) ? ans[1] : null }


function generate(curve) {
  const ecdh = crypto.createECDH(curve)
  ecdh.generateKeys()
  return ec_pem(ecdh, curve)
}

function clonePublic(ecdh) {
  let copy = ec_pem(null, ecdh.curve)
    copy.setPublicKey(ecdh.getPublicKey())
  return copy
}
function clonePrivate(ecdh) {
  let copy = ec_pem(null, ecdh.curve)
  copy.setPrivateKey(ecdh.getPrivateKey())
  return copy
}
function clone(ecdh, kind) {
  switch (kind) {
  case 'private':
    return clonePrivate(ecdh)
  case 'public': case false:
    return clonePublic(ecdh)

  case true: case null: case undefined:
    let copy = ec_pem(null, ecdh.curve)
    try { copy.setPrivateKey(ecdh.getPrivateKey()) }
    catch (err) { copy.setPublicKey(ecdh.getPublicKey()) }
    return copy

  default: throw new Error('Invalid kind for ec-pem::clone')
  }
}

// rx_base64_encoded includes url-safe characters and the '.' separator
const rx_base64_encoded = /^[A-Za-z0-9.+/=_-]+$/
function asUrlSafeBase64(sz) {
  // See [modified Base64 for URL](https://en.wikipedia.org/wiki/Base64#URL_applications)
  //  > …where the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_' … omitting the padding '='
  // Note: Buffer.from(sz, 'base64') correctly interprets this variant. String::toString('base64') just cannot produce it, unfortunately.
  if (sz && Buffer.isBuffer(sz)) sz = sz.toString('base64')
  return sz.replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'')
}

function toPrivateJSON(ecdh) {
  return {curve: ecdh.curve, private_key: asUrlSafeBase64(ecdh.getPrivateKey('base64'))}
}
function toPublicJSON(ecdh, format='compressed') {
  return {curve: ecdh.curve, public_key: asUrlSafeBase64(ecdh.getPublicKey('base64', format))}
}
function fromJSON(obj) {
  let ecdh = ec_pem(null, obj.curve)
  if (obj.private_key)
    ecdh.setPrivateKey(obj.private_key, 'base64')<commit_msg>Added optional curve argument to clone functions to allow cloning from generic crypto.createECDH instances<commit_after>'use strict'
const crypto = require('crypto')
const asn1 = require('asn1.js')

const ec_pem_api = {
  __proto__: Object.getPrototypeOf(crypto.createECDH('prime256v1')),
  encodePrivateKey(enc) { return encodePrivateKey(this, enc) },
  encodePublicKey(enc) { return encodePublicKey(this, enc) },
  sign(algorithm, ...optionalArgs) { return sign(this, algorithm, ...optionalArgs) },
  verify(algorithm, ...optionalArgs) { return verify(this, algorithm, ...optionalArgs) },
  clone(kind) { return clone(this, kind) },
  clonePublic() { return clonePublic(this) },
  clonePrivate() { return clonePrivate(this) },
  toPublicJSON(format) { return toPublicJSON(this, format) },
  toPrivateJSON() { return toPrivateJSON(this) },
  toPublicBase64(extra, format) { return toPublicBase64(this, extra, format) },
  toPrivateBase64(extra) { return toPrivateBase64(this, extra) },
  toPublicBuffer(format) { return toPublicBuffer(this, format) },
  toPrivateBuffer() { return toPrivateBuffer(this) },
}

const curveByKeySize = {
  '49': [ 'prime192v1' ],
  '49,24': [ 'prime192v1' ],
  '65': [ 'prime256v1' ],
  '65,32': [ 'prime256v1' ],
  '43': [ 'sect163k1', 'sect163r2' ],
  '43,21': [ 'sect163k1', 'sect163r2' ],
  '43,20': [ 'sect163k1', 'sect163r2' ],
  '57': [ 'secp224r1' ],
  '57,28': [ 'secp224r1' ],
  '61': [ 'sect233k1', 'sect233r1' ],
  '61,29': [ 'sect233k1', 'sect233r1' ],
  '61,28': [ 'sect233r1' ],
  '73': [ 'sect283k1', 'sect283r1' ],
  '73,36': [ 'sect283k1', 'sect283r1' ],
  '73,35': [ 'sect283k1', 'sect283r1' ],
  '97': [ 'secp384r1' ],
  '97,48': [ 'secp384r1' ],
  '105': [ 'sect409k1', 'sect409r1' ],
  '105,51': [ 'sect409k1', 'sect409r1' ],
  '133': [ 'secp521r1' ],
  '133,66': [ 'secp521r1' ],
  '133,65': [ 'secp521r1' ],
  '145': [ 'sect571k1', 'sect571r1' ],
  '145,71': [ 'sect571k1', 'sect571r1' ],
  '145,72': [ 'sect571k1', 'sect571r1' ] }

function ec_pem(ecdh, curve) {
  if ('string' === typeof ecdh && undefined === curve)
    curve = ecdh, ecdh = null;
  else if (!curve && ecdh)
    curve = ecdh.curve || inferCurve(ecdh, true)

  if (!curve)
    throw new Error("EC curve must be specified for PEM encoding support")

  if (null == ecdh)
    ecdh = crypto.createECDH(curve)

  Object.setPrototypeOf(ecdh, ec_pem_api)
  ecdh.curve = curve
  return ecdh
}

exports = module.exports = Object.assign(ec_pem, {
  ec_pem, ec_pem_api, generate, load, decode, sign, verify,
  loadPrivateKey, decodePrivateKey, encodePrivateKey,
  loadPublicKey, decodePublicKey, encodePublicKey,
  clonePrivate, clonePublic, clone,
  asUrlSafeBase64,
  toPrivateJSON, toPublicJSON, fromJSON,
  toPrivateBase64, toPublicBase64, fromBase64,
  toPrivateBuffer, toPublicBuffer, fromBuffer,
  inferCurve, inferCurveByLengths,
  pemDecodeRaw, pemEncodeRaw })


function inferCurve(ecdh, exactlyOne) {
  const keyLengths = [ecdh.getPublicKey().length]
  try { keyLengths.push(ecdh.getPrivateKey().length) }
  catch (err) {}
  return inferCurveByLengths(keyLengths, exactlyOne) }
function inferCurveByLengths(keyLengths, exactlyOne) {
  if (Number.isInteger(keyLengths))
    keyLengths = [keyLengths,]
  const ans = curveByKeySize[keyLengths]
  if (!exactlyOne) return ans
  return (ans.length === 1) ? ans[1] : null }


function generate(curve) {
  const ecdh = crypto.createECDH(curve)
  ecdh.generateKeys()
  return ec_pem(ecdh, curve)
}

function clonePublic(ecdh, curve) {
  let copy = ec_pem(null, curve || ecdh.curve)
    copy.setPublicKey(ecdh.getPublicKey())
  return copy
}
function clonePrivate(ecdh, curve) {
  let copy = ec_pem(null, curve || ecdh.curve)
  copy.setPrivateKey(ecdh.getPrivateKey())
  return copy
}
function clone(ecdh, kind, curve) {
  switch (kind) {
  case 'private':
    return clonePrivate(ecdh, curve)
  case 'public': case false:
    return clonePublic(ecdh, curve)

  case true: case null: case undefined:
    let copy = ec_pem(null, curve || ecdh.curve)
    try { copy.setPrivateKey(ecdh.getPrivateKey()) }
    catch (err) { copy.setPublicKey(ecdh.getPublicKey()) }
    return copy

  default: throw new Error('Invalid kind for ec-pem::clone')
  }
}

// rx_base64_encoded includes url-safe characters and the '.' separator
const rx_base64_encoded = /^[A-Za-z0-9.+/=_-]+$/
function asUrlSafeBase64(sz) {
  // See [modified Base64 for URL](https://en.wikipedia.org/wiki/Base64#URL_applications)
  //  > …where the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_' … omitting the padding '='
  // Note: Buffer.from(sz, 'base64') correctly interprets this variant. String::toString('base64') just cannot produce it, unfortunately.
  if (sz && Buffer.isBuffer(sz)) sz = sz.toString('base64')
  return sz.replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'')
}

function toPrivateJSON(ecdh) {
  return {curve: ecdh.curve, private_key: asUrlSafeBase64(ecdh.getPrivateKey('base64'))}
}
function toPublicJSON(ecdh, format='compressed') {
  return {curve: ecdh.curve, public_key: asUrlSafeBase64(ecdh.getPublicKey('base64', format))}
}
function fromJSON(obj) {
  let ecdh = ec_pem(null, obj.curve)
  if (obj.private_key)
    ecdh.setPrivateKey(obj.private_key, 'base64')
{'fraction_non_alphanumeric': 0.161174992752923, 'fraction_numerical': 0.05681708377621026, 'mean_word_length': 4.821147356580427, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, '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': '1000635', 'n_tokens_mistral': 4142, 'n_tokens_neox': 3783, 'n_words': 794}