'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.getEccLib = exports.initEccLib = void 0;
const _ECCLIB_CACHE = {};
/**
 * Initializes the ECC library with the provided instance.
 * If `eccLib` is `undefined`, the library will be cleared.
 * If `eccLib` is a new instance, it will be verified before setting it as the active library.
 *
 * @param eccLib The instance of the ECC library to initialize.
 * @param opts Extra initialization options. Use {DANGER_DO_NOT_VERIFY_ECCLIB:true} if ecc verification should not be executed. Not recommended!
 */
function initEccLib(eccLib, opts) {
  if (!eccLib) {
    // allow clearing the library
    _ECCLIB_CACHE.eccLib = eccLib;
  } else if (eccLib !== _ECCLIB_CACHE.eccLib) {
    if (!opts?.DANGER_DO_NOT_VERIFY_ECCLIB)
      // new instance, verify it
      verifyEcc(eccLib);
    _ECCLIB_CACHE.eccLib = eccLib;
  }
}
exports.initEccLib = initEccLib;
/**
 * Retrieves the ECC Library instance.
 * Throws an error if the ECC Library is not provided.
 * You must call initEccLib() with a valid TinySecp256k1Interface instance before calling this function.
 * @returns The ECC Library instance.
 * @throws Error if the ECC Library is not provided.
 */
function getEccLib() {
  if (!_ECCLIB_CACHE.eccLib)
    throw new Error(
      'No ECC Library provided. You must call initEccLib() with a valid TinySecp256k1Interface instance',
    );
  return _ECCLIB_CACHE.eccLib;
}
exports.getEccLib = getEccLib;
const h = hex => Buffer.from(hex, 'hex');
/**
 * Verifies the ECC functionality.
 *
 * @param ecc - The TinySecp256k1Interface object.
 */
function verifyEcc(ecc) {
  assert(typeof ecc.isXOnlyPoint === 'function');
  assert(
    ecc.isXOnlyPoint(
      h('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
    ),
  );
  assert(
    ecc.isXOnlyPoint(
      h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e'),
    ),
  );
  assert(
    ecc.isXOnlyPoint(
      h('f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'),
    ),
  );
  assert(
    ecc.isXOnlyPoint(
      h('0000000000000000000000000000000000000000000000000000000000000001'),
    ),
  );
  assert(
    !ecc.isXOnlyPoint(
      h('0000000000000000000000000000000000000000000000000000000000000000'),
    ),
  );
  assert(
    !ecc.isXOnlyPoint(
      h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'),
    ),
  );
  assert(typeof ecc.xOnlyPointAddTweak === 'function');
  tweakAddVectors.forEach(t => {
    const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak));
    if (t.result === null) {
      assert(r === null);
    } else {
      assert(r !== null);
      assert(r.parity === t.parity);
      assert(Buffer.from(r.xOnlyPubkey).equals(h(t.result)));
    }
  });
}
function assert(bool) {
  if (!bool) throw new Error('ecc library invalid');
}
const tweakAddVectors = [
  {
    pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
    tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
    parity: -1,
    result: null,
  },
  {
    pubkey: '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b',
    tweak: 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac',
    parity: 1,
    result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf',
  },
  {
    pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991',
    tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47',
    parity: 0,
    result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c',
  },
];
