'use strict';

var elliptic = require('elliptic');
var jsSha256 = require('js-sha256');
require('../types/public-keys/public-key.cjs');
require('../types/public-keys/public-key-sr25519-value.cjs');
require('../types/public-keys/public-key-ed25519-value.cjs');
require('../types/public-keys/public-key-secp256k1-value.cjs');
require('../types/public-keys/public-key-x25519-value.cjs');
require('../types/signatures/signature-value.cjs');
var types_signatures_signature = require('../types/signatures/signature.cjs');
var vc_crypto_constants = require('../vc/crypto/constants.cjs');
var keypairs_dockKeypair = require('./dock-keypair.cjs');
require('../utils/types/array.cjs');
var utils_types_bytes = require('../utils/types/bytes.cjs');
require('bs58');
require('multiformats/bases/base58');
require('varint');
require('../utils/encoding/ss-58.cjs');
require('../types/generic/typed-enum.cjs');
require('../utils/types/iterable.cjs');
require('../utils/types/object.cjs');
require('crypto');
require('../utils/interfaces.cjs');
require('../utils/assert.cjs');
require('../utils/error.cjs');
require('../utils/inheritance.cjs');
require('../utils/types/set.cjs');
require('../types/generic/with-base.cjs');
require('../types/generic/with-catch-null.cjs');
require('../types/generic/with-eq.cjs');
require('../types/generic/any-of.cjs');
require('../types/generic/with-from.cjs');
require('../types/generic/with-from-json-bytes.cjs');
require('../types/generic/typed-null.cjs');
require('../types/generic/create-placeholder.cjs');
require('blake2b');
require('../utils/types/string.cjs');
require('../types/generic/typed-bytes.cjs');
require('../types/generic/typed-string.cjs');
require('../types/generic/typed-array.cjs');
require('../types/generic/typed-tuple.cjs');
require('../types/generic/typed-number.cjs');
require('../types/generic/typed-set.cjs');
require('../types/generic/typed-map.cjs');
require('../types/generic/typed-struct.cjs');
require('uuid');
require('../types/generic/sized.cjs');
require('../utils/types/number.cjs');
require('../types/signatures/signature-ed25519-value.cjs');
require('../types/signatures/signature-secp256k1-value.cjs');
require('../types/signatures/signature-sr25519-value.cjs');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var elliptic__default = /*#__PURE__*/_interopDefault(elliptic);

const EC = elliptic__default.default.ec;
const secp256k1Curve = new EC('secp256k1');

function encodeDERInt(intBytes) {
  // Remove leading zeros
  let i = 0;
  while (i < intBytes.length && intBytes[i] === 0) {
    i++;
  }

  let trimmedBytes = intBytes.slice(i);

  // Ensure the integer is positive by adding a leading zero if needed
  // eslint-disable-next-line no-bitwise
  if (trimmedBytes[0] & 0x80) {
    trimmedBytes = Uint8Array.of(0, ...trimmedBytes);
  }

  const { length } = trimmedBytes;
  return [0x02, length, ...trimmedBytes];
}

class Secp256k1Keypair extends keypairs_dockKeypair {
  static Signature = types_signatures_signature.SignatureSecp256k1;

  static VerKeyType = vc_crypto_constants.EcdsaSecp256k1VerKeyName;

  static SeedSize = 32;

  /**
   *
   * Instantiates new `Secp256k1Keypair` from the provided source.
   * It can have one of two types: "entropy" or "private".
   *
   * @param {Uint8Array} entropyOrPrivate
   * @param {"entropy"|"private"} sourceType
   */
  constructor(entropyOrPrivate, sourceType = 'entropy') {
    let kp;
    switch (sourceType) {
      case 'entropy':
        if (entropyOrPrivate == null) {
          throw new Error('Entropy must be provided');
        }

        kp = secp256k1Curve.genKeyPair({
          entropy: entropyOrPrivate,
        });
        break;
      case 'private':
        kp = secp256k1Curve.keyFromPrivate(utils_types_bytes.normalizeToU8a(entropyOrPrivate));
        break;
      default:
        throw new Error(
          `Unknown source type: \`${sourceType}\`, it must be either "entropy" or "private"`,
        );
    }

    super(kp);
  }

  _publicKey() {
    // public key is in hex but doesn't contain a leading zero
    return utils_types_bytes.hexToU8a(`0x${this.keyPair.getPublic(true, 'hex')}`);
  }

  privateKey() {
    return utils_types_bytes.hexToU8a(`0x${this.keyPair.getPrivate('hex')}`);
  }

  _sign(message) {
    const hash = this.constructor.hash(message);
    const sig = this.keyPair.sign(hash, {
      canonical: true,
    });

    // The signature is recoverable in 65-byte { R | S | index } format
    const r = sig.r.toString('hex', 32);
    const s = sig.s.toString('hex', 32);
    const i = sig.recoveryParam.toString(16).padStart(2, '0');

    // Make it proper hex
    return utils_types_bytes.hexToU8a(`0x${r}${s}${i}`);
  }

  static signatureToDER(signature) {
    const sigBytes = utils_types_bytes.valueBytes(signature);
    if (sigBytes.length !== 65) {
      throw new Error(
        `Invalid signature length. Expected is 65 bytes, received ${sigBytes.length}`,
      );
    }
    // Extract R, S components
    const r = sigBytes.slice(0, 32); // First 32 bytes
    const s = sigBytes.slice(32, 64); // Next 32 bytes

    // Encode R and S into DER format
    const rEncoded = encodeDERInt(r);
    const sEncoded = encodeDERInt(s);

    // Calculate total length
    const totalLength = rEncoded.length + sEncoded.length;

    // Create Uint8Array for DER encoding
    const der = new Uint8Array(2 + totalLength); // 2 bytes for tag and length + total payload
    der[0] = 0x30; // DER sequence tag
    der[1] = totalLength; // Total length of R + S encoded

    // Copy encoded R and S into DER array
    der.set(rEncoded, 2);
    der.set(sEncoded, 2 + rEncoded.length);

    return der;
  }

  static hash(message) {
    return jsSha256.sha256.digest(message);
  }

  static verify(message, signature, publicKey) {
    let bytes = utils_types_bytes.valueBytes(signature);
    if (bytes.length === 65) {
      bytes = this.signatureToDER(bytes);
    }

    return secp256k1Curve.verify(
      this.hash(message),
      bytes,
      utils_types_bytes.valueBytes(publicKey),
    );
  }
}

module.exports = Secp256k1Keypair;
//# sourceMappingURL=keypair-secp256k1.cjs.map
