/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.security.spec; import java.math.BigInteger; import java.util.Arrays; /** * An Elliptic Curve with its necessary values. */ public class EllipticCurve { // Underlying finite field private final ECField field; // The first coefficient of the equation defining this elliptic curve private final BigInteger a; // The second coefficient of the equation defining this elliptic curve private final BigInteger b; // Bytes used during this elliptic curve generation, // if it was generated randomly private final byte[] seed; // Hash code private volatile int hash; /** * Creates a new {@code EllipticCurve} with the specified field, * coefficients and seed. * * @param field * the finite field of this elliptic curve. * @param a * the coefficient {@code a}. * @param b * the coefficient {@code b}. * @param seed * the seed used for the generation of the curve. * @throws IllegalArgumentException * if the specified coefficients are not in the specified field. */ public EllipticCurve(ECField field, BigInteger a, BigInteger b, byte[] seed) { this.field = field; if (this.field == null) { throw new NullPointerException("field == null"); } this.a = a; if (this.a == null) { throw new NullPointerException("a == null"); } this.b = b; if (this.b == null) { throw new NullPointerException("b == null"); } // make defensive copy if (seed == null) { this.seed = null; } else { this.seed = new byte[seed.length]; System.arraycopy(seed, 0, this.seed, 0, this.seed.length); } // check parameters for ECFieldFp and ECFieldF2m. // Check invariant: a and b must be in the field. // Check conditions for custom ECField are not specified. if (this.field instanceof ECFieldFp) { BigInteger p = ((ECFieldFp) this.field).getP(); if (this.a.signum() < 0 || this.a.compareTo(p) >= 0) { throw new IllegalArgumentException("the a is not in the field"); } if (this.b.signum() < 0 || this.b.compareTo(p) >= 0) { throw new IllegalArgumentException("the b is not in the field"); } } else if (this.field instanceof ECFieldF2m) { int fieldSizeInBits = this.field.getFieldSize(); if (!(this.a.bitLength() <= fieldSizeInBits)) { throw new IllegalArgumentException("the a is not in the field"); } if (!(this.b.bitLength() <= fieldSizeInBits)) { throw new IllegalArgumentException("the b is not in the field"); } } } /** * Creates a new {@code EllipticCurve} with the specified field and * coefficients. * * @param field * the finite field of this elliptic curve. * @param a * the coefficient {@code a}. * @param b * the coefficient {@code b}. * @throws IllegalArgumentException * if the specified coefficients are not in the specified field. */ public EllipticCurve(ECField field, BigInteger a, BigInteger b) { this(field, a, b, null); } /** * Returns the coefficient {@code a} of this elliptic curve. * * @return the coefficient {@code a} of this elliptic curve. */ public BigInteger getA() { return a; } /** * Returns the coefficient {@code b} of this elliptic curve. * * @return the coefficient {@code b} of this elliptic curve. */ public BigInteger getB() { return b; } /** * Returns the finite field of this elliptic curve. * * @return the finite field of this elliptic curve. */ public ECField getField() { return field; } /** * Returns a copy of the seed that was used to generate this elliptic curve. * * @return a copy of the seed that was used to generate this elliptic curve, * or {@code null} if none specified. */ public byte[] getSeed() { if (seed == null) { return null; } else { // return copy byte[] ret = new byte[seed.length]; System.arraycopy(seed, 0, ret, 0, ret.length); return ret; } } /** * Returns whether the specified object equals to this elliptic curve. * * @param other * the object to compare. * @return {@code true} if the specified object is equal to this elliptic * curve, otherwise {@code false}. */ public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof EllipticCurve)) { return false; } EllipticCurve otherEc = (EllipticCurve) other; return this.field.equals(otherEc.field) && this.a.equals(otherEc.a) && this.b.equals(otherEc.b) && Arrays.equals(this.seed, otherEc.seed); } /** * Returns the hashcode of this elliptic curve. * * @return the hashcode of this elliptic curve. */ public int hashCode() { // hash init is delayed if (hash == 0) { int hash0 = 11; hash0 = hash0 * 31 + field.hashCode(); hash0 = hash0 * 31 + a.hashCode(); hash0 = hash0 * 31 + b.hashCode(); if (seed != null) { for (int i = 0; i < seed.length; i++) { hash0 = hash0 * 31 + seed[i]; } } else { hash0 = hash0 * 31; } hash = hash0; } return hash; } }