operate method

List<int> operate(
  1. bool meta,
  2. StrobeOperation operation,
  3. List<int> dataConst,
  4. int length,
  5. bool more,
)

STROBE main duplexing mode.

Implementation

List<int> operate(
  bool meta,
  StrobeOperation operation,
  List<int> dataConst,
  int length,
  bool more,
) {
  int flags = operation.value;

  if (meta) {
    flags |= StrobeFlags.M;
  }

  List<int> data;
  if (((flags & (StrobeFlags.I | StrobeFlags.T)) !=
          (StrobeFlags.I | StrobeFlags.T)) &&
      ((flags & (StrobeFlags.I | StrobeFlags.A)) != StrobeFlags.A)) {
    if (length == 0) {
      throw ArgumentException.invalidOperationArguments(
        "operate",
        name: "length",
        reason: "A length should be set for this operation.",
      );
    }
    data = List<int>.filled(length, 0);
  } else {
    if (length != 0) {
      throw ArgumentException.invalidOperationArguments(
        "operate",
        name: "length",
        reason:
            "Output length must be zero except for PRF, send_MAC, and RATCHET operations.",
      );
    }
    data = dataConst.clone();
  }
  if (more) {
    if (flags != _curFlags) {
      throw ArgumentException.invalidOperationArguments(
        "operate",
        name: "length",
        reason: "Flag should be the same when streaming operations.",
      );
    }
  } else {
    // If [more] isn't set, this is a new operation. Do the begin_op sequence
    _op(flags);
    _curFlags = flags;
  }

  // Operation
  final bool cAfter =
      ((flags & (StrobeFlags.C | StrobeFlags.I | StrobeFlags.T)) ==
          (StrobeFlags.C | StrobeFlags.T));
  final bool cBefore = ((flags & StrobeFlags.C) != 0) && (!cAfter);

  _duplex(data, cBefore, cAfter, false);
  if ((flags & (StrobeFlags.I | StrobeFlags.A)) ==
      (StrobeFlags.I | StrobeFlags.A)) {
    return data;
  } else if ((flags & (StrobeFlags.I | StrobeFlags.T)) == StrobeFlags.T) {
    return data;
  } else if ((flags & (StrobeFlags.I | StrobeFlags.A | StrobeFlags.T)) ==
      (StrobeFlags.I | StrobeFlags.T)) {
    if (more) {
      throw ArgumentException.invalidOperationArguments(
        "operate",
        name: "more",
        reason:
            "Not supposed to check a MAC with the 'more' streaming option.",
      );
    }
    int failures = 0;
    for (final dataByte in data) {
      failures |= dataByte;
    }
    return [failures]; // 0 if correct, 1 if not
  }

  return List.empty();
}