Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECOperations.java
38830 views
/*1* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ec;2627import sun.security.ec.point.*;28import sun.security.util.math.*;29import sun.security.util.math.intpoly.*;3031import java.math.BigInteger;32import java.security.ProviderException;33import java.security.spec.ECFieldFp;34import java.security.spec.ECParameterSpec;35import java.security.spec.EllipticCurve;36import java.util.Collections;37import java.util.HashMap;38import java.util.Map;39import java.util.Optional;4041/*42* Elliptic curve point arithmetic for prime-order curves where a=-3.43* Formulas are derived from "Complete addition formulas for prime order44* elliptic curves" by Renes, Costello, and Batina.45*/4647public class ECOperations {4849/*50* An exception indicating a problem with an intermediate value produced51* by some part of the computation. For example, the signing operation52* will throw this exception to indicate that the r or s value is 0, and53* that the signing operation should be tried again with a different nonce.54*/55static class IntermediateValueException extends Exception {56private static final long serialVersionUID = 1;57}5859static final Map<BigInteger, IntegerFieldModuloP> fields;6061static final Map<BigInteger, IntegerFieldModuloP> orderFields;6263static {64Map<BigInteger, IntegerFieldModuloP> map = new HashMap<>();65map.put(IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256());66map.put(IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384());67map.put(IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521());68fields = Collections.unmodifiableMap(map);69map = new HashMap<>();70map.put(P256OrderField.MODULUS, new P256OrderField());71map.put(P384OrderField.MODULUS, new P384OrderField());72map.put(P521OrderField.MODULUS, new P521OrderField());73orderFields = Collections.unmodifiableMap(map);74}7576public static Optional<ECOperations> forParameters(ECParameterSpec params) {7778EllipticCurve curve = params.getCurve();79if (!(curve.getField() instanceof ECFieldFp)) {80return Optional.empty();81}82ECFieldFp primeField = (ECFieldFp) curve.getField();8384BigInteger three = BigInteger.valueOf(3);85if (!primeField.getP().subtract(curve.getA()).equals(three)) {86return Optional.empty();87}88IntegerFieldModuloP field = fields.get(primeField.getP());89if (field == null) {90return Optional.empty();91}9293IntegerFieldModuloP orderField = orderFields.get(params.getOrder());94if (orderField == null) {95return Optional.empty();96}9798ImmutableIntegerModuloP b = field.getElement(curve.getB());99ECOperations ecOps = new ECOperations(b, orderField);100return Optional.of(ecOps);101}102103final ImmutableIntegerModuloP b;104final SmallValue one;105final SmallValue two;106final SmallValue three;107final SmallValue four;108final ProjectivePoint.Immutable neutral;109private final IntegerFieldModuloP orderField;110111public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {112this.b = b.fixed();113this.orderField = orderField;114115this.one = b.getField().getSmallValue(1);116this.two = b.getField().getSmallValue(2);117this.three = b.getField().getSmallValue(3);118this.four = b.getField().getSmallValue(4);119120IntegerFieldModuloP field = b.getField();121this.neutral = new ProjectivePoint.Immutable(field.get0(),122field.get1(), field.get0());123}124125public IntegerFieldModuloP getField() {126return b.getField();127}128public IntegerFieldModuloP getOrderField() {129return orderField;130}131132protected ProjectivePoint.Immutable getNeutral() {133return neutral;134}135136public boolean isNeutral(Point p) {137ProjectivePoint<?> pp = (ProjectivePoint<?>) p;138139IntegerModuloP z = pp.getZ();140141IntegerFieldModuloP field = z.getField();142int byteLength = (field.getSize().bitLength() + 7) / 8;143byte[] zBytes = z.asByteArray(byteLength);144return allZero(zBytes);145}146147byte[] seedToScalar(byte[] seedBytes)148throws IntermediateValueException {149150// Produce a nonce from the seed using FIPS 186-4,section B.5.1:151// Per-Message Secret Number Generation Using Extra Random Bits152// or153// Produce a scalar from the seed using FIPS 186-4, section B.4.1:154// Key Pair Generation Using Extra Random Bits155156// To keep the implementation simple, sample in the range [0,n)157// and throw IntermediateValueException in the (unlikely) event158// that the result is 0.159160// Get 64 extra bits and reduce in to the nonce161int seedBits = orderField.getSize().bitLength() + 64;162if (seedBytes.length * 8 < seedBits) {163throw new ProviderException("Incorrect seed length: " +164seedBytes.length * 8 + " < " + seedBits);165}166167// input conversion only works on byte boundaries168// clear high-order bits of last byte so they don't influence nonce169int lastByteBits = seedBits % 8;170if (lastByteBits != 0) {171int lastByteIndex = seedBits / 8;172byte mask = (byte) (0xFF >>> (8 - lastByteBits));173seedBytes[lastByteIndex] &= mask;174}175176int seedLength = (seedBits + 7) / 8;177IntegerModuloP scalarElem =178orderField.getElement(seedBytes, 0, seedLength, (byte) 0);179int scalarLength = (orderField.getSize().bitLength() + 7) / 8;180byte[] scalarArr = new byte[scalarLength];181scalarElem.asByteArray(scalarArr);182if (ECOperations.allZero(scalarArr)) {183throw new IntermediateValueException();184}185return scalarArr;186}187188/*189* Compare all values in the array to 0 without branching on any value190*191*/192public static boolean allZero(byte[] arr) {193byte acc = 0;194for (int i = 0; i < arr.length; i++) {195acc |= arr[i];196}197return acc == 0;198}199200/*201* 4-bit branchless array lookup for projective points.202*/203private void lookup4(ProjectivePoint.Immutable[] arr, int index,204ProjectivePoint.Mutable result, IntegerModuloP zero) {205206for (int i = 0; i < 16; i++) {207int xor = index ^ i;208int bit3 = (xor & 0x8) >>> 3;209int bit2 = (xor & 0x4) >>> 2;210int bit1 = (xor & 0x2) >>> 1;211int bit0 = (xor & 0x1);212int inverse = bit0 | bit1 | bit2 | bit3;213int set = 1 - inverse;214215ProjectivePoint.Immutable pi = arr[i];216result.conditionalSet(pi, set);217}218}219220private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,221MutableIntegerModuloP t1, MutableIntegerModuloP t2,222MutableIntegerModuloP t3, MutableIntegerModuloP t4) {223224for (int i = 0; i < 4; i++) {225setDouble(p, t0, t1, t2, t3, t4);226}227}228229/**230* Multiply an affine point by a scalar and return the result as a mutable231* point.232*233* @param affineP the point234* @param s the scalar as a little-endian array235* @return the product236*/237public MutablePoint multiply(AffinePoint affineP, byte[] s) {238239// 4-bit windowed multiply with branchless lookup.240// The mixed addition is faster, so it is used to construct the array241// at the beginning of the operation.242243IntegerFieldModuloP field = affineP.getX().getField();244ImmutableIntegerModuloP zero = field.get0();245// temporaries246MutableIntegerModuloP t0 = zero.mutable();247MutableIntegerModuloP t1 = zero.mutable();248MutableIntegerModuloP t2 = zero.mutable();249MutableIntegerModuloP t3 = zero.mutable();250MutableIntegerModuloP t4 = zero.mutable();251252ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);253result.getY().setValue(field.get1().mutable());254255ProjectivePoint.Immutable[] pointMultiples =256new ProjectivePoint.Immutable[16];257// 0P is neutral---same as initial result value258pointMultiples[0] = result.fixed();259260ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);261ps.setValue(affineP);262// 1P = P263pointMultiples[1] = ps.fixed();264265// the rest are calculated using mixed point addition266for (int i = 2; i < 16; i++) {267setSum(ps, affineP, t0, t1, t2, t3, t4);268pointMultiples[i] = ps.fixed();269}270271ProjectivePoint.Mutable lookupResult = ps.mutable();272273for (int i = s.length - 1; i >= 0; i--) {274275double4(result, t0, t1, t2, t3, t4);276277int high = (0xFF & s[i]) >>> 4;278lookup4(pointMultiples, high, lookupResult, zero);279setSum(result, lookupResult, t0, t1, t2, t3, t4);280281double4(result, t0, t1, t2, t3, t4);282283int low = 0xF & s[i];284lookup4(pointMultiples, low, lookupResult, zero);285setSum(result, lookupResult, t0, t1, t2, t3, t4);286}287288return result;289290}291292/*293* Point double294*/295private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,296MutableIntegerModuloP t1, MutableIntegerModuloP t2,297MutableIntegerModuloP t3, MutableIntegerModuloP t4) {298299t0.setValue(p.getX()).setSquare();300t1.setValue(p.getY()).setSquare();301t2.setValue(p.getZ()).setSquare();302t3.setValue(p.getX()).setProduct(p.getY());303t4.setValue(p.getY()).setProduct(p.getZ());304305t3.setSum(t3);306p.getZ().setProduct(p.getX());307308p.getZ().setProduct(two);309310p.getY().setValue(t2).setProduct(b);311p.getY().setDifference(p.getZ());312313p.getX().setValue(p.getY()).setProduct(two);314p.getY().setSum(p.getX());315p.getY().setReduced();316p.getX().setValue(t1).setDifference(p.getY());317318p.getY().setSum(t1);319p.getY().setProduct(p.getX());320p.getX().setProduct(t3);321322t3.setValue(t2).setProduct(two);323t2.setSum(t3);324p.getZ().setProduct(b);325326t2.setReduced();327p.getZ().setDifference(t2);328p.getZ().setDifference(t0);329t3.setValue(p.getZ()).setProduct(two);330p.getZ().setReduced();331p.getZ().setSum(t3);332t0.setProduct(three);333334t0.setDifference(t2);335t0.setProduct(p.getZ());336p.getY().setSum(t0);337338t4.setSum(t4);339p.getZ().setProduct(t4);340341p.getX().setDifference(p.getZ());342p.getZ().setValue(t4).setProduct(t1);343344p.getZ().setProduct(four);345346}347348/*349* Mixed point addition. This method constructs new temporaries each time350* it is called. For better efficiency, the method that reuses temporaries351* should be used if more than one sum will be computed.352*/353public void setSum(MutablePoint p, AffinePoint p2) {354355IntegerModuloP zero = p.getField().get0();356MutableIntegerModuloP t0 = zero.mutable();357MutableIntegerModuloP t1 = zero.mutable();358MutableIntegerModuloP t2 = zero.mutable();359MutableIntegerModuloP t3 = zero.mutable();360MutableIntegerModuloP t4 = zero.mutable();361setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);362363}364365/*366* Mixed point addition367*/368private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,369MutableIntegerModuloP t0, MutableIntegerModuloP t1,370MutableIntegerModuloP t2, MutableIntegerModuloP t3,371MutableIntegerModuloP t4) {372373t0.setValue(p.getX()).setProduct(p2.getX());374t1.setValue(p.getY()).setProduct(p2.getY());375t3.setValue(p2.getX()).setSum(p2.getY());376t4.setValue(p.getX()).setSum(p.getY());377p.getX().setReduced();378t3.setProduct(t4);379t4.setValue(t0).setSum(t1);380381t3.setDifference(t4);382t4.setValue(p2.getY()).setProduct(p.getZ());383t4.setSum(p.getY());384385p.getY().setValue(p2.getX()).setProduct(p.getZ());386p.getY().setSum(p.getX());387t2.setValue(p.getZ());388p.getZ().setProduct(b);389390p.getX().setValue(p.getY()).setDifference(p.getZ());391p.getX().setReduced();392p.getZ().setValue(p.getX()).setProduct(two);393p.getX().setSum(p.getZ());394395p.getZ().setValue(t1).setDifference(p.getX());396p.getX().setSum(t1);397p.getY().setProduct(b);398399t1.setValue(t2).setProduct(two);400t2.setSum(t1);401t2.setReduced();402p.getY().setDifference(t2);403404p.getY().setDifference(t0);405p.getY().setReduced();406t1.setValue(p.getY()).setProduct(two);407p.getY().setSum(t1);408409t1.setValue(t0).setProduct(two);410t0.setSum(t1);411t0.setDifference(t2);412413t1.setValue(t4).setProduct(p.getY());414t2.setValue(t0).setProduct(p.getY());415p.getY().setValue(p.getX()).setProduct(p.getZ());416417p.getY().setSum(t2);418p.getX().setProduct(t3);419p.getX().setDifference(t1);420421p.getZ().setProduct(t4);422t1.setValue(t3).setProduct(t0);423p.getZ().setSum(t1);424425}426427/*428* Projective point addition429*/430private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,431MutableIntegerModuloP t0, MutableIntegerModuloP t1,432MutableIntegerModuloP t2, MutableIntegerModuloP t3,433MutableIntegerModuloP t4) {434435t0.setValue(p.getX()).setProduct(p2.getX());436t1.setValue(p.getY()).setProduct(p2.getY());437t2.setValue(p.getZ()).setProduct(p2.getZ());438439t3.setValue(p.getX()).setSum(p.getY());440t4.setValue(p2.getX()).setSum(p2.getY());441t3.setProduct(t4);442443t4.setValue(t0).setSum(t1);444t3.setDifference(t4);445t4.setValue(p.getY()).setSum(p.getZ());446447p.getY().setValue(p2.getY()).setSum(p2.getZ());448t4.setProduct(p.getY());449p.getY().setValue(t1).setSum(t2);450451t4.setDifference(p.getY());452p.getX().setSum(p.getZ());453p.getY().setValue(p2.getX()).setSum(p2.getZ());454455p.getX().setProduct(p.getY());456p.getY().setValue(t0).setSum(t2);457p.getY().setAdditiveInverse().setSum(p.getX());458p.getY().setReduced();459460p.getZ().setValue(t2).setProduct(b);461p.getX().setValue(p.getY()).setDifference(p.getZ());462p.getZ().setValue(p.getX()).setProduct(two);463464p.getX().setSum(p.getZ());465p.getX().setReduced();466p.getZ().setValue(t1).setDifference(p.getX());467p.getX().setSum(t1);468469p.getY().setProduct(b);470t1.setValue(t2).setSum(t2);471t2.setSum(t1);472t2.setReduced();473474p.getY().setDifference(t2);475p.getY().setDifference(t0);476p.getY().setReduced();477t1.setValue(p.getY()).setSum(p.getY());478479p.getY().setSum(t1);480t1.setValue(t0).setProduct(two);481t0.setSum(t1);482483t0.setDifference(t2);484t1.setValue(t4).setProduct(p.getY());485t2.setValue(t0).setProduct(p.getY());486487p.getY().setValue(p.getX()).setProduct(p.getZ());488p.getY().setSum(t2);489p.getX().setProduct(t3);490491p.getX().setDifference(t1);492p.getZ().setProduct(t4);493t1.setValue(t3).setProduct(t0);494495p.getZ().setSum(t1);496497}498}499500501