1 /*
   2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.security.spec;
  27 
  28 import java.math.BigInteger;
  29 import java.util.Arrays;
  30 
  31 /**
  32  * This immutable class holds the necessary values needed to represent
  33  * an elliptic curve.
  34  *
  35  * @see ECField
  36  * @see ECFieldFp
  37  * @see ECFieldF2m
  38  *
  39  * @author Valerie Peng
  40  *
  41  * @since 1.5
  42  */
  43 public class EllipticCurve {
  44 
  45     private final ECField field;
  46     private final BigInteger a;
  47     private final BigInteger b;
  48     private final byte[] seed;
  49 
  50     // Check coefficient c is a valid element in ECField field.
  51     private static void checkValidity(ECField field, BigInteger c,
  52         String cName) {
  53         // can only perform check if field is ECFieldFp or ECFieldF2m.
  54         if (field instanceof ECFieldFp) {
  55             BigInteger p = ((ECFieldFp)field).getP();
  56             if (p.compareTo(c) != 1) {
  57                 throw new IllegalArgumentException(cName + " is too large");
  58             } else if (c.signum() < 0) {
  59                 throw new IllegalArgumentException(cName + " is negative");
  60             }
  61         } else if (field instanceof ECFieldF2m) {
  62             int m = ((ECFieldF2m)field).getM();
  63             if (c.bitLength() > m) {
  64                 throw new IllegalArgumentException(cName + " is too large");
  65             }
  66         }
  67     }
  68 
  69     /**
  70      * Creates an elliptic curve with the specified elliptic field
  71      * <code>field</code> and the coefficients <code>a</code> and
  72      * <code>b</code>.
  73      * @param field the finite field that this elliptic curve is over.
  74      * @param a the first coefficient of this elliptic curve.
  75      * @param b the second coefficient of this elliptic curve.
  76      * @exception NullPointerException if <code>field</code>,
  77      * <code>a</code>, or <code>b</code> is null.
  78      * @exception IllegalArgumentException if <code>a</code>
  79      * or <code>b</code> is not null and not in <code>field</code>.
  80      */
  81     public EllipticCurve(ECField field, BigInteger a,
  82                          BigInteger b) {
  83         this(field, a, b, null);
  84     }
  85 
  86     /**
  87      * Creates an elliptic curve with the specified elliptic field
  88      * <code>field</code>, the coefficients <code>a</code> and
  89      * <code>b</code>, and the <code>seed</code> used for curve generation.
  90      * @param field the finite field that this elliptic curve is over.
  91      * @param a the first coefficient of this elliptic curve.
  92      * @param b the second coefficient of this elliptic curve.
  93      * @param seed the bytes used during curve generation for later
  94      * validation. Contents of this array are copied to protect against
  95      * subsequent modification.
  96      * @exception NullPointerException if <code>field</code>,
  97      * <code>a</code>, or <code>b</code> is null.
  98      * @exception IllegalArgumentException if <code>a</code>
  99      * or <code>b</code> is not null and not in <code>field</code>.
 100      */
 101     public EllipticCurve(ECField field, BigInteger a,
 102                          BigInteger b, byte[] seed) {
 103         if (field == null) {
 104             throw new NullPointerException("field is null");
 105         }
 106         if (a == null) {
 107             throw new NullPointerException("first coefficient is null");
 108         }
 109         if (b == null) {
 110             throw new NullPointerException("second coefficient is null");
 111         }
 112         checkValidity(field, a, "first coefficient");
 113         checkValidity(field, b, "second coefficient");
 114         this.field = field;
 115         this.a = a;
 116         this.b = b;
 117         if (seed != null) {
 118             this.seed = seed.clone();
 119         } else {
 120             this.seed = null;
 121         }
 122     }
 123 
 124     /**
 125      * Returns the finite field <code>field</code> that this
 126      * elliptic curve is over.
 127      * @return the field <code>field</code> that this curve
 128      * is over.
 129      */
 130     public ECField getField() {
 131         return field;
 132     }
 133 
 134     /**
 135      * Returns the first coefficient <code>a</code> of the
 136      * elliptic curve.
 137      * @return the first coefficient <code>a</code>.
 138      */
 139     public BigInteger getA() {
 140         return a;
 141     }
 142 
 143     /**
 144      * Returns the second coefficient <code>b</code> of the
 145      * elliptic curve.
 146      * @return the second coefficient <code>b</code>.
 147      */
 148     public BigInteger getB() {
 149         return b;
 150     }
 151 
 152     /**
 153      * Returns the seeding bytes <code>seed</code> used
 154      * during curve generation. May be null if not specified.
 155      * @return the seeding bytes <code>seed</code>. A new
 156      * array is returned each time this method is called.
 157      */
 158     public byte[] getSeed() {
 159         if (seed == null) return null;
 160         else return seed.clone();
 161     }
 162 
 163     /**
 164      * Compares this elliptic curve for equality with the
 165      * specified object.
 166      * @param obj the object to be compared.
 167      * @return true if <code>obj</code> is an instance of
 168      * EllipticCurve and the field, A, and B match, false otherwise.
 169      */
 170     public boolean equals(Object obj) {
 171         if (this == obj) return true;
 172         if (obj instanceof EllipticCurve) {
 173             EllipticCurve curve = (EllipticCurve) obj;
 174             if ((field.equals(curve.field)) &&
 175                 (a.equals(curve.a)) &&
 176                 (b.equals(curve.b))) {
 177                     return true;
 178             }
 179         }
 180         return false;
 181     }
 182 
 183     /**
 184      * Returns a hash code value for this elliptic curve.
 185      * @return a hash code value computed from the hash codes of the field, A,
 186      * and B, as follows:
 187      * <code>
 188      *     (field.hashCode() << 6) + (a.hashCode() << 4) + (b.hashCode() << 2)
 189      * </code>
 190      */
 191     public int hashCode() {
 192         return (field.hashCode() << 6 +
 193             (a.hashCode() << 4) +
 194             (b.hashCode() << 2));
 195     }
 196 }