1 /* 2 * Copyright (c) 2003, 2019, 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. checkValidity(ECField field, BigInteger c, String cName)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} and the coefficients {@code a} and 72 * {@code b}. 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 * @throws NullPointerException if {@code field}, 77 * {@code a}, or {@code b} is null. 78 * @throws IllegalArgumentException if {@code a} 79 * or {@code b} is not null and not in {@code field}. 80 */ EllipticCurve(ECField field, BigInteger a, BigInteger b)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}, the coefficients {@code a} and 89 * {@code b}, and the {@code seed} 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 * @throws NullPointerException if {@code field}, 97 * {@code a}, or {@code b} is null. 98 * @throws IllegalArgumentException if {@code a} 99 * or {@code b} is not null and not in {@code field}. 100 */ EllipticCurve(ECField field, BigInteger a, BigInteger b, byte[] seed)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} that this 126 * elliptic curve is over. 127 * @return the field {@code field} that this curve 128 * is over. 129 */ getField()130 public ECField getField() { 131 return field; 132 } 133 134 /** 135 * Returns the first coefficient {@code a} of the 136 * elliptic curve. 137 * @return the first coefficient {@code a}. 138 */ getA()139 public BigInteger getA() { 140 return a; 141 } 142 143 /** 144 * Returns the second coefficient {@code b} of the 145 * elliptic curve. 146 * @return the second coefficient {@code b}. 147 */ getB()148 public BigInteger getB() { 149 return b; 150 } 151 152 /** 153 * Returns the seeding bytes {@code seed} used 154 * during curve generation. May be null if not specified. 155 * @return the seeding bytes {@code seed}. A new 156 * array is returned each time this method is called. 157 */ getSeed()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} is an instance of 168 * EllipticCurve and the field, A, and B match, false otherwise. 169 */ equals(Object obj)170 public boolean equals(Object obj) { 171 if (this == obj) return true; 172 173 return obj instanceof EllipticCurve other 174 && field.equals(other.field) 175 && a.equals(other.a) 176 && b.equals(other.b); 177 } 178 179 /** 180 * Returns a hash code value for this elliptic curve. 181 * @return a hash code value computed from the hash codes of the field, A, 182 * and B, as follows: 183 * <pre>{@code 184 * (field.hashCode() << 6) + (a.hashCode() << 4) + (b.hashCode() << 2) 185 * }</pre> 186 */ hashCode()187 public int hashCode() { 188 return (field.hashCode() << 6 + 189 (a.hashCode() << 4) + 190 (b.hashCode() << 2)); 191 } 192 } 193