generateMds<F extends PastaFieldElement<F>> static method

MdsGenerateResult<F> generateMds<F extends PastaFieldElement<F>>(
  1. Grain<F> grain,
  2. int t,
  3. int select,
  4. F one,
  5. F zero,
)

Implementation

static MdsGenerateResult<F> generateMds<F extends PastaFieldElement<F>>(
  Grain<F> grain,
  int t,
  int select,
  F one,
  F zero,
) {
  List<F> xs = [];
  List<F> ys = [];
  List<List<F>> mds = [];
  int counter = select;
  while (true) {
    // Generate two lists of unique field elements
    while (true) {
      List<F> vals = List.generate(
        2 * t,
        (_) => grain.nextFieldElementWithoutRejection(),
      );

      // Check uniqueness
      List<F> unique = List.from(vals);
      unique.sort((a, b) => a.compareTo(b));
      unique = unique.toSet().toList();

      if (vals.length == unique.length) {
        xs = vals.sublist(0, t);
        ys = vals.sublist(t);
        break;
      }
    }

    // Skip if select counter not yet zero
    if (counter != 0) {
      counter -= 1;
      continue;
    }

    // Generate MDS matrix: a_ij = 1 / (x_i + y_j)
    mds = List.generate(
      t,
      (i) => List.generate(t, (j) {
        final sum = xs[i] + ys[j];
        final s = sum.invert();
        if (s == null) {
          throw PoseidonException("Division by zero.");
        }
        return s;
      }),
    );

    break;
  }

  // Compute inverse MDS
  List<List<F>> mdsInv = List.generate(
    t,
    (_) => List.generate(t, (_) => zero),
  );

  F lagrange(List<F> arr, int j, F x) {
    final xj = arr[j];
    F acc = one;
    for (int m = 0; m < arr.length; m++) {
      if (m == j) continue;
      final denom = xj - arr[m];
      final denomInv = denom.invert();
      if (denomInv == null) {
        throw PoseidonException("Division by zero.");
      }
      acc = acc * (x - arr[m]) * denomInv;
    }
    return acc;
  }

  // Negate ys for positive Cauchy formulation
  final negYs = ys.map((y) => -y).toList();

  for (int i = 0; i < t; i++) {
    for (int j = 0; j < t; j++) {
      mdsInv[i][j] =
          (xs[j] - negYs[i]) *
          lagrange(xs, j, negYs[i]) *
          lagrange(negYs, i, xs[j]);
    }
  }
  return MdsGenerateResult(mds: mds, mdsInv: mdsInv);
}