"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var NodeJsStyleCrypto_exports = {};
__export(NodeJsStyleCrypto_exports, {
  NodeJsStyleCrypto: () => NodeJsStyleCrypto
});
module.exports = __toCommonJS(NodeJsStyleCrypto_exports);
var import_Environment = require("#environment/Environment.js");
var import_MatterError = require("#MatterError.js");
var import_Bytes = require("#util/Bytes.js");
var import_Entropy = require("#util/Entropy.js");
var import_Error = require("#util/Error.js");
var import_Crypto = require("./Crypto.js");
var import_CryptoError = require("./CryptoError.js");
var import_EcdsaSignature = require("./EcdsaSignature.js");
var import_Key = require("./Key.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class NodeJsStyleCrypto extends import_Crypto.Crypto {
  implementationName = "Node.js";
  /**
   * The auto-detected Node.js crypto module, set at module load time if available.
   */
  static detectedCrypto;
  #crypto;
  constructor(crypto) {
    super();
    this.#crypto = crypto ?? NodeJsStyleCrypto.detectedCrypto;
  }
  encrypt(key, data, nonce, aad) {
    const cipher = this.#crypto.createCipheriv(import_Crypto.CRYPTO_ENCRYPT_ALGORITHM, import_Bytes.Bytes.of(key), import_Bytes.Bytes.of(nonce), {
      authTagLength: import_Crypto.CRYPTO_AUTH_TAG_LENGTH
    });
    if (aad !== void 0) {
      cipher.setAAD(import_Bytes.Bytes.of(aad), { plaintextLength: data.byteLength });
    }
    const encrypted = cipher.update(import_Bytes.Bytes.of(data));
    cipher.final();
    return import_Bytes.Bytes.concat(import_Bytes.Bytes.of(encrypted), import_Bytes.Bytes.of(cipher.getAuthTag()));
  }
  decrypt(key, encrypted, nonce, aad) {
    const cipher = this.#crypto.createDecipheriv(import_Crypto.CRYPTO_ENCRYPT_ALGORITHM, import_Bytes.Bytes.of(key), import_Bytes.Bytes.of(nonce), {
      authTagLength: import_Crypto.CRYPTO_AUTH_TAG_LENGTH
    });
    const data = import_Bytes.Bytes.of(encrypted);
    const plaintextLength = data.length - import_Crypto.CRYPTO_AUTH_TAG_LENGTH;
    if (aad !== void 0) {
      cipher.setAAD(import_Bytes.Bytes.of(aad), { plaintextLength });
    }
    cipher.setAuthTag(data.slice(plaintextLength));
    const result = cipher.update(data.slice(0, plaintextLength));
    try {
      cipher.final();
    } catch (e) {
      throw new import_CryptoError.CryptoDecryptError(`${import_Crypto.CRYPTO_ENCRYPT_ALGORITHM} decryption failed: ${(0, import_Error.asError)(e).message}`);
    }
    return import_Bytes.Bytes.of(result);
  }
  randomBytes(length) {
    return import_Bytes.Bytes.of(this.#crypto.randomBytes(length));
  }
  ecdhGeneratePublicKey() {
    const ecdh = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh.generateKeys();
    return { publicKey: import_Bytes.Bytes.of(ecdh.getPublicKey()), ecdh };
  }
  ecdhGeneratePublicKeyAndSecret(peerPublicKey) {
    const ecdh = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh.generateKeys();
    return {
      publicKey: import_Bytes.Bytes.of(ecdh.getPublicKey()),
      sharedSecret: import_Bytes.Bytes.of(ecdh.computeSecret(import_Bytes.Bytes.of(peerPublicKey)))
    };
  }
  async #hashAsyncIteratorData(hasher, iteratorFunc) {
    while (true) {
      const { value, done } = await iteratorFunc();
      if (value === void 0 || done) break;
      hasher.update(import_Bytes.Bytes.of(value));
    }
  }
  computeHash(data, algorithm = "SHA-256") {
    const hasher = this.#crypto.createHash(algorithm);
    if (Array.isArray(data)) {
      data.forEach((chunk) => hasher.update(import_Bytes.Bytes.of(chunk)));
    } else if (import_Bytes.Bytes.isBytes(data)) {
      hasher.update(import_Bytes.Bytes.of(data));
    } else {
      let iteratorFunc;
      if ("read" in data && typeof data.read === "function") {
        iteratorFunc = data.read.bind(data);
      } else if ("next" in data && typeof data.next === "function") {
        iteratorFunc = data.next.bind(data);
      } else {
        throw new import_MatterError.ImplementationError(`Invalid data type for computeHash with algorithm ${algorithm}`);
      }
      return this.#hashAsyncIteratorData(hasher, iteratorFunc).then(() => import_Bytes.Bytes.of(hasher.digest()));
    }
    return import_Bytes.Bytes.of(hasher.digest());
  }
  createPbkdf2Key(secret, salt, iteration, keyLength) {
    return new Promise((resolver, rejecter) => {
      this.#crypto.pbkdf2(
        import_Bytes.Bytes.of(secret),
        import_Bytes.Bytes.of(salt),
        iteration,
        keyLength,
        import_Crypto.CRYPTO_HASH_ALGORITHM,
        (error, key) => {
          if (error !== null) rejecter(error);
          resolver(import_Bytes.Bytes.of(key));
        }
      );
    });
  }
  createHkdfKey(secret, salt, info, length = import_Crypto.CRYPTO_SYMMETRIC_KEY_LENGTH) {
    return new Promise((resolver, rejecter) => {
      this.#crypto.hkdf(
        import_Crypto.CRYPTO_HASH_ALGORITHM,
        import_Bytes.Bytes.of(secret),
        import_Bytes.Bytes.of(salt),
        import_Bytes.Bytes.of(info),
        length,
        (error, key) => {
          if (error !== null) rejecter(error);
          resolver(import_Bytes.Bytes.of(key));
        }
      );
    });
  }
  signHmac(key, data) {
    const hmac = this.#crypto.createHmac(import_Crypto.CRYPTO_HASH_ALGORITHM, import_Bytes.Bytes.of(key));
    hmac.update(import_Bytes.Bytes.of(data));
    return import_Bytes.Bytes.of(hmac.digest());
  }
  signEcdsa(privateKey, data) {
    const signer = this.#crypto.createSign(import_Crypto.CRYPTO_HASH_ALGORITHM);
    if (Array.isArray(data)) {
      data.forEach((chunk) => signer.update(import_Bytes.Bytes.of(chunk)));
    } else {
      signer.update(import_Bytes.Bytes.of(data));
    }
    return new import_EcdsaSignature.EcdsaSignature(
      import_Bytes.Bytes.of(
        signer.sign({
          key: privateKey,
          format: "jwk",
          type: "pkcs8",
          dsaEncoding: "ieee-p1363"
        })
      )
    );
  }
  verifyEcdsa(publicKey, data, signature) {
    const verifier = this.#crypto.createVerify(import_Crypto.CRYPTO_HASH_ALGORITHM);
    verifier.update(import_Bytes.Bytes.of(data));
    const success = verifier.verify(
      {
        key: publicKey,
        format: "jwk",
        type: "spki",
        dsaEncoding: "ieee-p1363"
      },
      import_Bytes.Bytes.of(signature.bytes)
    );
    if (!success) throw new import_CryptoError.CryptoVerifyError("Signature verification failed");
  }
  createKeyPair() {
    const ecdh = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh.generateKeys();
    const privateKey = new Uint8Array(import_Crypto.CRYPTO_EC_KEY_BYTES);
    const nodePrivateKey = ecdh.getPrivateKey();
    privateKey.set(nodePrivateKey, import_Crypto.CRYPTO_EC_KEY_BYTES - nodePrivateKey.length);
    return (0, import_Key.PrivateKey)(privateKey, { publicKey: import_Bytes.Bytes.of(ecdh.getPublicKey()) });
  }
  generateDhSecret(key, peerKey) {
    const ecdh = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh.setPrivateKey(import_Bytes.Bytes.of(key.privateBits));
    return import_Bytes.Bytes.of(ecdh.computeSecret(import_Bytes.Bytes.of(peerKey.publicBits)));
  }
  ecMultiply(point, scalar) {
    const {
      p256: { Point },
      pow,
      mod: modFn
    } = import_Crypto.ec;
    const curve = Point.CURVE();
    const scalarVal = import_Bytes.Bytes.asBigInt(import_Bytes.Bytes.of(scalar));
    if (scalarVal === 0n || scalarVal + 1n >= curve.n) {
      return Point.fromBytes(import_Bytes.Bytes.of(point)).multiply(scalarVal).toBytes(false);
    }
    const pointBuf = import_Bytes.Bytes.of(point);
    const p = curve.p;
    const ecdh1 = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh1.setPrivateKey(import_Bytes.Bytes.of(scalar));
    const rx = import_Bytes.Bytes.asBigInt(import_Bytes.Bytes.of(ecdh1.computeSecret(pointBuf)));
    const rx2 = modFn(rx * rx, p);
    const rhs = modFn(rx2 * rx + (p - 3n) * rx + curve.b, p);
    const ry = pow(rhs, (p + 1n) / 4n, p);
    const ecdh2 = this.#crypto.createECDH(import_Crypto.CRYPTO_EC_CURVE);
    ecdh2.setPrivateKey(import_Bytes.Bytes.of(import_Bytes.Bytes.fromBigInt(scalarVal + 1n, 32)));
    const expectedX = import_Bytes.Bytes.asBigInt(import_Bytes.Bytes.of(ecdh2.computeSecret(pointBuf)));
    const result = new Uint8Array(65);
    result[0] = 4;
    result.set(import_Bytes.Bytes.of(import_Bytes.Bytes.fromBigInt(rx, 32)), 1);
    result.set(import_Bytes.Bytes.of(import_Bytes.Bytes.fromBigInt(ry, 32)), 33);
    if (Point.fromBytes(result).add(Point.fromBytes(pointBuf)).x === expectedX) {
      return result;
    }
    result.set(import_Bytes.Bytes.of(import_Bytes.Bytes.fromBigInt(p - ry, 32)), 33);
    return result;
  }
}
const nodeCrypto = globalThis.process?.getBuiltinModule?.("crypto");
if (nodeCrypto?.createECDH) {
  NodeJsStyleCrypto.detectedCrypto = nodeCrypto;
  const nodeJsStyleCrypto = new NodeJsStyleCrypto();
  import_Environment.Environment.default.set(import_Entropy.Entropy, nodeJsStyleCrypto);
  import_Environment.Environment.default.set(import_Crypto.Crypto, nodeJsStyleCrypto);
}
//# sourceMappingURL=NodeJsStyleCrypto.js.map
