/**
   * Invert this field element and return the result. The inverse is found via Fermat's little
   * theorem: a^p congruent a mod p and therefore a^(p-2) congruent a^-1 mod p
   *
   * @return The inverse of this field element.
   */
  public Ed25519FieldElement invert() {
    Ed25519FieldElement f0, f1;

    // comments describe how exponent is created

    // 2 == 2 * 1
    f0 = this.square();

    // 9 == 9
    f1 = this.pow2to9();

    // 11 == 9 + 2
    f0 = f0.multiply(f1);

    // 2^252 - 2^2
    f1 = this.pow2to252sub4();

    // 2^255 - 2^5
    for (int i = 1; i < 4; ++i) {
      f1 = f1.square();
    }

    // 2^255 - 21
    return f1.multiply(f0);
  }
  @Override
  public boolean equals(final Object obj) {
    if (!(obj instanceof Ed25519FieldElement)) {
      return false;
    }

    final Ed25519FieldElement f = (Ed25519FieldElement) obj;
    return this.encode().equals(f.encode());
  }
  /**
   * Encodes a given field element in its 32 byte 2^8 bit representation. This is done in two steps.
   * Step 1: Reduce the value of the field element modulo p. Step 2: Convert the field element to
   * the 32 byte representation.
   *
   * @return Encoded field element (32 bytes).
   */
  public Ed25519EncodedFieldElement encode() {
    // Step 1:
    final Ed25519FieldElement g = this.modP();
    final int[] gValues = g.getRaw();
    final int h0 = gValues[0];
    final int h1 = gValues[1];
    final int h2 = gValues[2];
    final int h3 = gValues[3];
    final int h4 = gValues[4];
    final int h5 = gValues[5];
    final int h6 = gValues[6];
    final int h7 = gValues[7];
    final int h8 = gValues[8];
    final int h9 = gValues[9];

    // Step 2:
    final byte[] s = new byte[32];
    s[0] = (byte) (h0);
    s[1] = (byte) (h0 >> 8);
    s[2] = (byte) (h0 >> 16);
    s[3] = (byte) ((h0 >> 24) | (h1 << 2));
    s[4] = (byte) (h1 >> 6);
    s[5] = (byte) (h1 >> 14);
    s[6] = (byte) ((h1 >> 22) | (h2 << 3));
    s[7] = (byte) (h2 >> 5);
    s[8] = (byte) (h2 >> 13);
    s[9] = (byte) ((h2 >> 21) | (h3 << 5));
    s[10] = (byte) (h3 >> 3);
    s[11] = (byte) (h3 >> 11);
    s[12] = (byte) ((h3 >> 19) | (h4 << 6));
    s[13] = (byte) (h4 >> 2);
    s[14] = (byte) (h4 >> 10);
    s[15] = (byte) (h4 >> 18);
    s[16] = (byte) (h5);
    s[17] = (byte) (h5 >> 8);
    s[18] = (byte) (h5 >> 16);
    s[19] = (byte) ((h5 >> 24) | (h6 << 1));
    s[20] = (byte) (h6 >> 7);
    s[21] = (byte) (h6 >> 15);
    s[22] = (byte) ((h6 >> 23) | (h7 << 3));
    s[23] = (byte) (h7 >> 5);
    s[24] = (byte) (h7 >> 13);
    s[25] = (byte) ((h7 >> 21) | (h8 << 4));
    s[26] = (byte) (h8 >> 4);
    s[27] = (byte) (h8 >> 12);
    s[28] = (byte) ((h8 >> 20) | (h9 << 6));
    s[29] = (byte) (h9 >> 2);
    s[30] = (byte) (h9 >> 10);
    s[31] = (byte) (h9 >> 18);

    return new Ed25519EncodedFieldElement(s);
  }
  /**
   * Computes this field element to the power of (2^9) and returns the result.
   *
   * @return This field element to the power of (2^9).
   */
  private Ed25519FieldElement pow2to9() {
    Ed25519FieldElement f;

    // 2 == 2 * 1
    f = this.square();

    // 4 == 2 * 2
    f = f.square();

    // 8 == 2 * 4
    f = f.square();

    // 9 == 1 + 8
    return this.multiply(f);
  }
  /**
   * Calculates and returns one of the square roots of u / v.
   *
   * <pre>{@code
   * x = (u * v^3) * (u * v^7)^((p - 5) / 8) ==> x^2 = +-(u / v).
   * }</pre>
   *
   * Note that this means x can be sqrt(u / v), -sqrt(u / v), +i * sqrt(u / v), -i * sqrt(u / v).
   *
   * @param u The nominator of the fraction.
   * @param v The denominator of the fraction.
   * @return The square root of u / v.
   */
  public static Ed25519FieldElement sqrt(final Ed25519FieldElement u, final Ed25519FieldElement v) {
    Ed25519FieldElement x;
    final Ed25519FieldElement v3;

    // v3 = v^3
    v3 = v.square().multiply(v);

    // x = (v3^2) * v * u = u * v^7
    x = v3.square().multiply(v).multiply(u);

    //  x = (u * v^7)^((q - 5) / 8)
    x = x.pow2to252sub4().multiply(x); // 2^252 - 3

    // x = u * v^3 * (u * v^7)^((q - 5) / 8)
    x = v3.multiply(u).multiply(x);

    return x;
  }
  /**
   * Computes this field element to the power of (2^252 - 4) and returns the result. This is a
   * helper function for calculating the square root.
   *
   * @return This field element to the power of (2^252 - 4).
   */
  private Ed25519FieldElement pow2to252sub4() {
    Ed25519FieldElement f0, f1, f2;

    // 2 == 2 * 1
    f0 = this.square();

    // 9
    f1 = this.pow2to9();

    // 11 == 9 + 2
    f0 = f0.multiply(f1);

    // 22 == 2 * 11
    f0 = f0.square();

    // 31 == 22 + 9
    f0 = f1.multiply(f0);

    // 2^6 - 2^1
    f1 = f0.square();

    // 2^10 - 2^5
    for (int i = 1; i < 5; ++i) {
      f1 = f1.square();
    }

    // 2^10 - 2^0
    f0 = f1.multiply(f0);

    // 2^11 - 2^1
    f1 = f0.square();

    // 2^20 - 2^10
    for (int i = 1; i < 10; ++i) {
      f1 = f1.square();
    }

    // 2^20 - 2^0
    f1 = f1.multiply(f0);

    // 2^21 - 2^1
    f2 = f1.square();

    // 2^40 - 2^20
    for (int i = 1; i < 20; ++i) {
      f2 = f2.square();
    }

    // 2^40 - 2^0
    f1 = f2.multiply(f1);

    // 2^41 - 2^1
    f1 = f1.square();

    // 2^50 - 2^10
    for (int i = 1; i < 10; ++i) {
      f1 = f1.square();
    }

    // 2^50 - 2^0
    f0 = f1.multiply(f0);

    // 2^51 - 2^1
    f1 = f0.square();

    // 2^100 - 2^50
    for (int i = 1; i < 50; ++i) {
      f1 = f1.square();
    }

    // 2^100 - 2^0
    f1 = f1.multiply(f0);

    // 2^101 - 2^1
    f2 = f1.square();

    // 2^200 - 2^100
    for (int i = 1; i < 100; ++i) {
      f2 = f2.square();
    }

    // 2^200 - 2^0
    f1 = f2.multiply(f1);

    // 2^201 - 2^1
    f1 = f1.square();

    // 2^250 - 2^50
    for (int i = 1; i < 50; ++i) {
      f1 = f1.square();
    }

    // 2^250 - 2^0
    f0 = f1.multiply(f0);

    // 2^251 - 2^1
    f0 = f0.square();

    // 2^252 - 2^2
    return f0.square();
  }