sqrt method

Implementation

@override
FieldSqrtResult<Bls12NativeFp2> sqrt() {
  // Zero is a quadratic residue; sqrt(0) = 0
  if (isZero()) {
    return FieldSqrtResult(Bls12NativeFp2.zero(), true);
  }

  // a1 = self^((p - 3) / 4)
  final a1 = _exp(
    BigInt.parse(
      "1000602388805416848354447456433976039139220704984751971333014534031007912622709466110671907282253916009473568139946",
    ),
  );

  // alpha = a1^2 * self = self^((p - 1) / 2)
  final alpha = a1.square() * this;

  // x0 = self^((p + 1) / 4)
  final x0 = a1 * this;

  // Case 1: alpha == -1
  if (alpha == -Bls12NativeFp2.one()) {
    final sqrt = Bls12NativeFp2(c0: -x0.c1, c1: x0.c0);

    // Verify sqrt^2 == self
    return FieldSqrtResult(sqrt, sqrt.square() == this);
  }

  // Case 2: general case
  final sqrt =
      (alpha + Bls12NativeFp2.one())._exp(
        BigInt.parse(
          "2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893",
        ),
      ) *
      x0;

  // Final verification
  return FieldSqrtResult(sqrt, sqrt.square() == this);
}