1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security.spec; 19 20import java.math.BigInteger; 21import java.util.Arrays; 22 23/** 24 * The parameters specifying a <i>characteristic 2 finite field</i> of an 25 * elliptic curve. 26 */ 27public class ECFieldF2m implements ECField { 28 // Mid terms array length for trinomial basis 29 private static final int TPB_MID_LEN = 1; 30 // Mid terms array length for pentanomial basis 31 private static final int PPB_MID_LEN = 3; 32 // All terms number for trinomial basis 33 private static final int TPB_LEN = TPB_MID_LEN + 2; 34 // All terms number for pentanomial basis 35 private static final int PPB_LEN = PPB_MID_LEN + 2; 36 // m value 37 private final int m; 38 // Reduction polynomial 39 private final BigInteger rp; 40 // Mid term(s) of reduction polynomial 41 private final int[] ks; 42 43 /** 44 * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a normal 45 * basis. 46 * 47 * @param m 48 * the exponent {@code m} for the number of elements. 49 * @throws IllegalArgumentException 50 * if {@code m <= zero}. 51 */ 52 public ECFieldF2m(int m) { 53 this.m = m; 54 if (this.m <= 0) { 55 throw new IllegalArgumentException("m <= 0"); 56 } 57 this.rp = null; 58 this.ks = null; 59 } 60 61 /** 62 * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a polynomial 63 * basis and the reduction polynomial based on {@code rp}. 64 * <p> 65 * The reduction polynomial must be either <i>trinomial</i> or 66 * <i>pentanomial</i>. 67 * 68 * @param m 69 * the exponent {@code m} for the number of elements. 70 * @param rp 71 * the base of the reduction polynomial with the n-th bit 72 * corresponding to the n-th coefficient of the reduction 73 * polynomial. 74 * @throws IllegalArgumentException 75 * if {@code m <= zero} or the {@code rp} is invalid. 76 */ 77 public ECFieldF2m(int m, BigInteger rp) { 78 this.m = m; 79 if (this.m <= 0) { 80 throw new IllegalArgumentException("m <= 0"); 81 } 82 this.rp = rp; 83 if (this.rp == null) { 84 throw new NullPointerException("rp == null"); 85 } 86 // the leftmost bit must be (m+1)-th one, 87 // set bits count must be 3 or 5, 88 // bits 0 and m must be set 89 int rp_bc = this.rp.bitCount(); 90 if ((this.rp.bitLength() != (m+1)) || 91 (rp_bc != TPB_LEN && rp_bc != PPB_LEN) || 92 (!this.rp.testBit(0) || !this.rp.testBit(m)) ) { 93 throw new IllegalArgumentException("rp is invalid"); 94 } 95 96 // setup ks using rp: 97 // allocate for mid terms only 98 ks = new int[rp_bc-2]; 99 // find midterm orders and set ks accordingly 100 BigInteger rpTmp = rp.clearBit(0); 101 for (int i=ks.length-1; i>=0; i-- ) { 102 ks[i] = rpTmp.getLowestSetBit(); 103 rpTmp = rpTmp.clearBit(ks[i]); 104 } 105 } 106 107 /** 108 * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with 109 * a polynomial basis and the reduction polynomial based on {@code ks}. 110 * <p> 111 * The reduction polynomial must be either <i>trinomial</i> or 112 * <i>pentanomial</i>. 113 * 114 * @param m 115 * the exponent {@code m} for the number of elements. 116 * @param ks 117 * the base of the reduction polynomial with coefficients 118 * given in descending order. 119 * @throws IllegalArgumentException 120 * if {@code m <= zero} or the reduction polynomial is not 121 * valid. 122 */ 123 public ECFieldF2m(int m, int[] ks) { 124 this.m = m; 125 if (this.m <= 0) { 126 throw new IllegalArgumentException("m <= 0"); 127 } 128 // Defensively copies array parameter 129 // to prevent subsequent modification. 130 // NPE as specified if ks is null 131 this.ks = new int[ks.length]; 132 System.arraycopy(ks, 0, this.ks, 0, this.ks.length); 133 134 // no need to check for null already 135 if (this.ks.length != TPB_MID_LEN && this.ks.length != PPB_MID_LEN) { 136 // must be either trinomial or pentanomial basis 137 throw new IllegalArgumentException("the length of ks is invalid"); 138 } 139 // trinomial basis: 140 // check that m > k >= 1, where k is ks[0] 141 // pentanomial basis: 142 // check that m > k3 > k2 > k1 >= 1 143 // and kx in descending order, where 144 // k3 is ks[0], k2 is ks[1], k1 is ks[2] 145 boolean checkFailed = false; 146 int prev = this.m; 147 for (int i=0; i<this.ks.length; i++) { 148 if (this.ks[i] < prev) { 149 prev = this.ks[i]; 150 continue; 151 } 152 checkFailed = true; 153 break; 154 } 155 if (checkFailed || prev < 1) { 156 throw new IllegalArgumentException("ks is invalid"); 157 } 158 159 // Setup rp using ks: 160 // bits 0 and m always set 161 BigInteger rpTmp = BigInteger.ONE.setBit(this.m); 162 // set remaining bits according to ks 163 for (int i=0; i<this.ks.length; i++) { 164 rpTmp = rpTmp.setBit(this.ks[i]); 165 } 166 rp = rpTmp; 167 } 168 169 /** 170 * Returns whether the specified object equals to this finite field. 171 * 172 * @param obj 173 * the object to compare to this finite field. 174 * @return {@code true} if the specified object is equal to this finite field, 175 * otherwise {@code false}. 176 */ 177 public boolean equals(Object obj) { 178 // object equals to itself 179 if (this == obj) { 180 return true; 181 } 182 if (obj instanceof ECFieldF2m) { 183 ECFieldF2m o = (ECFieldF2m)obj; 184 // check m 185 if (this.m == o.m) { 186 // check rp 187 if (this.rp == null) { 188 if (o.rp == null) { 189 // fields both with normal basis 190 return true; 191 } 192 } else { 193 // at least this field with polynomial basis 194 // check that rp match 195 // return this.rp.equals(o.rp); 196 return Arrays.equals(this.ks, o.ks); 197 } 198 } 199 } 200 return false; 201 } 202 203 /** 204 * Returns the size of this finite field (in bits). 205 * 206 * @return the size of this finite field (in bits). 207 */ 208 public int getFieldSize() { 209 return m; 210 } 211 212 /** 213 * Returns the exponent {@code m} for this finite field, with {@code 2^m} as 214 * the number of elements. 215 * 216 * @return the exponent {@code m} for this finite field 217 */ 218 public int getM() { 219 return m; 220 } 221 222 /** 223 * Returns a copy of the integer array containing the order of the middle 224 * term(s) of the reduction polynomial for a polynomial basis. 225 * 226 * @return a copy of the integer array containing the order of the middle 227 * term(s) of the reduction polynomial for a polynomial basis or 228 * {@code null} for a normal basis. 229 */ 230 public int[] getMidTermsOfReductionPolynomial() { 231 // Defensively copies private array 232 // to prevent subsequent modification 233 // was: return ks == null ? null : (int[])ks.clone(); 234 if (ks == null) { 235 return null; 236 } else { 237 int[] ret = new int[ks.length]; 238 System.arraycopy(ks, 0, ret, 0, ret.length); 239 return ret; 240 } 241 } 242 243 /** 244 * Returns the base of the reduction polynomial with the n-th bit 245 * corresponding to the n-th coefficient of the reduction polynomial for a 246 * polynomial basis. 247 * 248 * @return the base of the reduction polynomial with the n-th bit 249 * corresponding to the n-th coefficient of the reduction polynomial 250 * for a polynomial basis or {@code null} for a normal basis. 251 */ 252 public BigInteger getReductionPolynomial() { 253 return rp; 254 } 255 256 /** 257 * Returns the hashcode value for this finite field. 258 * 259 * @return the hashcode value for this finite field. 260 */ 261 public int hashCode() { 262 return rp == null ? m : m + rp.hashCode(); 263 } 264} 265