@Override
  public byte[] computeMac() throws GeneralSecurityException {
    if (finalized) {
      throw new IllegalStateException(
          "Can not compute after computing the MAC tag. Please create a new object.");
    }
    if (key.getParameters().getVariant() == Variant.LEGACY) {
      update(ByteBuffer.wrap(FORMAT_VERSION));
    }
    finalized = true;

    byte[] mLast;
    if (localStash.remaining() > 0) {
      // An incomplete block or an empty input.
      byte[] lastChunkToPad = Arrays.copyOf(localStash.array(), localStash.position());
      mLast = Bytes.xor(AesUtil.cmacPad(lastChunkToPad), subKey2);
    } else {
      // Block is full (remaining() == 0).
      mLast = Bytes.xor(localStash.array(), 0, subKey1, 0, AesUtil.BLOCK_SIZE);
    }

    return Bytes.concat(
        key.getOutputPrefix().toByteArray(),
        Arrays.copyOf(
            aes.doFinal(Bytes.xor(mLast, x.array())),
            key.getParameters().getCryptographicTagSizeBytes()));
  }
We need this AES-block sized buffer in order to account for the possibility of data not
arriving in perfect blocks, and also because we never know which block is going to be the last,
so we need to cache some data unprocessed between calls to update().

Invariant: between calls we have: 0 <= localStash.position < 16, and localStash is a suffix of
data so far, such that the rest is divisible by 16.
java_src/src/main/java/com/google/crypto/tink/mac/internal/ChunkedAesCmacComputation.java