/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { CryptoInputError } from "#crypto/CryptoError.js";
import { Bytes } from "#util/Bytes.js";
import { Aes } from "./Aes.js";
import { WordArray } from "./WordArray.js";
const BLOCK_SIZE = 16;
const RB = 135;
const ZERO_BLOCK = new Uint8Array(BLOCK_SIZE);
function aesEcbEncryptBlock(aes, block) {
  const words = WordArray.fromByteArray(block);
  aes.encrypt(words);
  const out = new Uint8Array(BLOCK_SIZE);
  const view = new DataView(out.buffer);
  for (let i = 0; i < 4; i++) view.setInt32(i * 4, words[i]);
  return out;
}
function leftShift1(input) {
  const out = new Uint8Array(input.length);
  let carry = 0;
  for (let i = input.length - 1; i >= 0; i--) {
    const b = input[i];
    out[i] = b << 1 & 255 | carry;
    carry = (b & 128) >> 7;
  }
  return out;
}
function xorInto(target, source, offset = 0) {
  for (let i = 0; i < BLOCK_SIZE; i++) target[i] ^= source[offset + i];
}
function generateSubkeys(aes) {
  const l = aesEcbEncryptBlock(aes, ZERO_BLOCK);
  const k1 = leftShift1(l);
  if ((l[0] & 128) !== 0) k1[BLOCK_SIZE - 1] ^= RB;
  const k2 = leftShift1(k1);
  if ((k1[0] & 128) !== 0) k2[BLOCK_SIZE - 1] ^= RB;
  return { k1, k2 };
}
function cmac(key, message) {
  if (key.length !== 16) {
    throw new CryptoInputError(`AES-CMAC key must be 16 bytes, got ${key.length}`);
  }
  const aes = Aes(Bytes.of(key));
  const { k1, k2 } = generateSubkeys(aes);
  const numBlocks = Math.max(1, Math.ceil(message.length / BLOCK_SIZE));
  const lastBlockComplete = message.length > 0 && message.length % BLOCK_SIZE === 0;
  const lastBlock = new Uint8Array(BLOCK_SIZE);
  const lastBlockOffset = (numBlocks - 1) * BLOCK_SIZE;
  if (lastBlockComplete) {
    lastBlock.set(message.subarray(lastBlockOffset, lastBlockOffset + BLOCK_SIZE));
    xorInto(lastBlock, k1);
  } else {
    const remaining = message.length - lastBlockOffset;
    lastBlock.set(message.subarray(lastBlockOffset, lastBlockOffset + remaining));
    lastBlock[remaining] = 128;
    xorInto(lastBlock, k2);
  }
  const x = new Uint8Array(BLOCK_SIZE);
  for (let i = 0; i < numBlocks - 1; i++) {
    xorInto(x, message, i * BLOCK_SIZE);
    x.set(aesEcbEncryptBlock(aes, x));
  }
  xorInto(x, lastBlock);
  return aesEcbEncryptBlock(aes, x);
}
export {
  cmac
};
//# sourceMappingURL=Cmac.js.map
