"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 = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
var Spake2p_exports = {};
__export(Spake2p_exports, {
  Spake2p: () => Spake2p
});
module.exports = __toCommonJS(Spake2p_exports);
var import_MatterError = require("../MatterError.js");
var import_Bytes = require("../util/Bytes.js");
var import_DataWriter = require("../util/DataWriter.js");
var import_Crypto = require("./Crypto.js");
var import_CryptoConstants = require("./CryptoConstants.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const {
  p256: { Point },
  mod
} = import_Crypto.ec;
const M = Point.fromHex("02886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f");
const N = Point.fromHex("03d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49");
const M_BYTES = M.toBytes(false);
const N_BYTES = N.toBytes(false);
const BASE_BYTES = Point.BASE.toBytes(false);
const CRYPTO_W_SIZE_BYTES = import_CryptoConstants.CRYPTO_GROUP_SIZE_BYTES + 8;
class Spake2p {
  #crypto;
  #context;
  #random;
  #w0;
  static async computeW0W1(crypto, { iterations, salt }, pin) {
    const pinWriter = new import_DataWriter.DataWriter(import_Bytes.Endian.Little);
    pinWriter.writeUInt32(pin);
    const ws = import_Bytes.Bytes.of(
      await crypto.createPbkdf2Key(pinWriter.toByteArray(), salt, iterations, CRYPTO_W_SIZE_BYTES * 2)
    );
    const curve = Point.CURVE();
    const w0 = mod(import_Bytes.Bytes.asBigInt(ws.slice(0, 40)), curve.n);
    const w1 = mod(import_Bytes.Bytes.asBigInt(ws.slice(40, 80)), curve.n);
    return { w0, w1 };
  }
  static async computeW0L(crypto, pbkdfParameters, pin) {
    const { w0, w1 } = await this.computeW0W1(crypto, pbkdfParameters, pin);
    const L = crypto.ecMultiply(BASE_BYTES, import_Bytes.Bytes.fromBigInt(w1, 32));
    return { w0, L };
  }
  static create(crypto, context, w0) {
    const curve = Point.CURVE();
    const random = crypto.randomBigInt(32, curve.n);
    return new Spake2p(crypto, context, random, w0);
  }
  constructor(crypto, context, random, w0) {
    this.#crypto = crypto;
    this.#context = context;
    this.#random = random;
    this.#w0 = w0;
  }
  computeX() {
    const randomBytes = import_Bytes.Bytes.fromBigInt(this.#random, 32);
    const w0Bytes = import_Bytes.Bytes.fromBigInt(this.#w0, 32);
    const baseR = this.#crypto.ecMultiply(BASE_BYTES, randomBytes);
    const mW0 = this.#crypto.ecMultiply(M_BYTES, w0Bytes);
    return this.#crypto.ecAdd(baseR, mW0);
  }
  computeY() {
    const randomBytes = import_Bytes.Bytes.fromBigInt(this.#random, 32);
    const w0Bytes = import_Bytes.Bytes.fromBigInt(this.#w0, 32);
    const baseR = this.#crypto.ecMultiply(BASE_BYTES, randomBytes);
    const nW0 = this.#crypto.ecMultiply(N_BYTES, w0Bytes);
    return this.#crypto.ecAdd(baseR, nW0);
  }
  async computeSecretAndVerifiersFromY(w1, X, Y) {
    try {
      Point.fromBytes(import_Bytes.Bytes.of(Y)).assertValidity();
    } catch (error) {
      throw new import_MatterError.InternalError(`Y is not on the curve: ${error.message}`);
    }
    const nW0 = this.#crypto.ecNegate(this.#crypto.ecMultiply(N_BYTES, import_Bytes.Bytes.fromBigInt(this.#w0, 32)));
    const yNwo = this.#crypto.ecAdd(Y, nW0);
    const Z = this.#crypto.ecMultiply(yNwo, import_Bytes.Bytes.fromBigInt(this.#random, 32));
    const V = this.#crypto.ecMultiply(yNwo, import_Bytes.Bytes.fromBigInt(w1, 32));
    return this.computeSecretAndVerifiers(X, Y, Z, V);
  }
  async computeSecretAndVerifiersFromX(L, X, Y) {
    try {
      Point.fromBytes(import_Bytes.Bytes.of(X)).assertValidity();
    } catch (error) {
      throw new import_MatterError.InternalError(`X is not on the curve: ${error.message}`);
    }
    const mW0 = this.#crypto.ecNegate(this.#crypto.ecMultiply(M_BYTES, import_Bytes.Bytes.fromBigInt(this.#w0, 32)));
    const xSubM = this.#crypto.ecAdd(X, mW0);
    const Z = this.#crypto.ecMultiply(xSubM, import_Bytes.Bytes.fromBigInt(this.#random, 32));
    const V = this.#crypto.ecMultiply(L, import_Bytes.Bytes.fromBigInt(this.#random, 32));
    return this.computeSecretAndVerifiers(X, Y, Z, V);
  }
  async computeSecretAndVerifiers(X, Y, Z, V) {
    const TT_HASH = import_Bytes.Bytes.of(await this.computeTranscriptHash(X, Y, Z, V));
    const Ka = TT_HASH.slice(0, 16);
    const Ke = TT_HASH.slice(16, 32);
    const KcAB = import_Bytes.Bytes.of(
      await this.#crypto.createHkdfKey(Ka, new Uint8Array(0), import_Bytes.Bytes.fromString("ConfirmationKeys"), 32)
    );
    const KcA = KcAB.slice(0, 16);
    const KcB = KcAB.slice(16, 32);
    const hAY = await this.#crypto.signHmac(KcA, Y);
    const hBX = await this.#crypto.signHmac(KcB, X);
    return { Ke, hAY, hBX };
  }
  computeTranscriptHash(X, Y, Z, V) {
    const TTwriter = new import_DataWriter.DataWriter(import_Bytes.Endian.Little);
    this.addToContext(TTwriter, this.#context);
    this.addToContext(TTwriter, import_Bytes.Bytes.fromString(""));
    this.addToContext(TTwriter, import_Bytes.Bytes.fromString(""));
    this.addToContext(TTwriter, M_BYTES);
    this.addToContext(TTwriter, N_BYTES);
    this.addToContext(TTwriter, X);
    this.addToContext(TTwriter, Y);
    this.addToContext(TTwriter, Z);
    this.addToContext(TTwriter, V);
    this.addToContext(TTwriter, import_Bytes.Bytes.fromBigInt(this.#w0, 32));
    return this.#crypto.computeHash(TTwriter.toByteArray());
  }
  addToContext(TTwriter, data) {
    TTwriter.writeUInt64(data.byteLength);
    TTwriter.writeByteArray(data);
  }
}
//# sourceMappingURL=Spake2p.js.map
