/**
 * EdDSA-Java by str4d
 * <p>
 * To the extent possible under law, the person who associated CC0 with EdDSA-Java has waived all
 * copyright and related or neighboring rights to EdDSA-Java.
 * <p>
 * You should have received a copy of the CC0 legalcode along with this work. If not, see
 * <https://creativecommons.org/publicdomain/zero/1.0/>.
 */
package org.mariadb.jdbc.internal.com.send.ed25519.math;

import java.io.Serializable;

/**
 * An EdDSA finite field. Includes several pre-computed values.
 *
 * @author str4d
 */
public class Field implements Serializable {

  private static final long serialVersionUID = 8746587465875676L;

  public final FieldElement ZERO;
  public final FieldElement ONE;
  public final FieldElement TWO;
  public final FieldElement FOUR;
  public final FieldElement FIVE;
  public final FieldElement EIGHT;

  private final int b;
  private final FieldElement q;
  /**
   * q-2
   */
  private final FieldElement qm2;
  /**
   * (q-5) / 8
   */
  private final FieldElement qm5d8;
  private final Encoding enc;

  public Field(int b, byte[] q, Encoding enc) {
    this.b = b;
    this.enc = enc;
    this.enc.setField(this);

    this.q = fromByteArray(q);

    // Set up constants
    ZERO = fromByteArray(Constants.ZERO);
    ONE = fromByteArray(Constants.ONE);
    TWO = fromByteArray(Constants.TWO);
    FOUR = fromByteArray(Constants.FOUR);
    FIVE = fromByteArray(Constants.FIVE);
    EIGHT = fromByteArray(Constants.EIGHT);

    // Precompute values
    qm2 = this.q.subtract(TWO);
    qm5d8 = this.q.subtract(FIVE).divide(EIGHT);
  }

  public FieldElement fromByteArray(byte[] x) {
    return enc.decode(x);
  }

  public int getb() {
    return b;
  }

  public FieldElement getQ() {
    return q;
  }

  public FieldElement getQm2() {
    return qm2;
  }

  public FieldElement getQm5d8() {
    return qm5d8;
  }

  public Encoding getEncoding() {
    return enc;
  }

  @Override
  public int hashCode() {
    return q.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof org.mariadb.jdbc.internal.com.send.ed25519.math.Field)) {
      return false;
    }
    org.mariadb.jdbc.internal.com.send.ed25519.math.Field f = (org.mariadb.jdbc.internal.com.send.ed25519.math.Field) obj;
    return b == f.b && q.equals(f.q);
  }
}
