Java Code Examples for org.bouncycastle.math.ec.ECCurve

The following examples show how to use org.bouncycastle.math.ec.ECCurve. These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source Project: eosio-java   Source File: EOSFormatter.java    License: MIT License 6 votes vote down vote up
/**
 * * Copyright 2011 Google Inc. * Copyright 2014 Andreas Schildbach * Copyright 2014-2016 the
 * libsecp256k1 contributors * * Licensed 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.
 * <p>
 * The method was modified to match what we need
 * <p>
 * Decompress a compressed public key (x co-ord and low-bit of y-coord).
 */
private static ECPoint decompressKey(BigInteger xBN, boolean yBit, AlgorithmEmployed keyType) {
    ECCurve.Fp curve;

    switch (keyType) {
        case SECP256R1:
            curve = (ECCurve.Fp) ecParamsR1.getCurve();
            break;

        default:
            curve = (ECCurve.Fp) ecParamsK1.getCurve();
            break;
    }

    X9IntegerConverter x9 = new X9IntegerConverter();
    byte[] compEnc = x9.integerToBytes(xBN, 1 + x9.getByteLength(curve));
    compEnc[0] = (byte) (yBit ? COMPRESSED_PUBLIC_KEY_BYTE_INDICATOR_NEGATIVE_Y
            : COMPRESSED_PUBLIC_KEY_BYTE_INDICATOR_POSITIVE_Y);
    return curve.decodePoint(compEnc);
}
 
Example 2
Source Project: JCMathLib   Source File: Util.java    License: MIT License 6 votes vote down vote up
private static ECPoint ECPointDeSerialization(byte[] serialized_point,
        int offset, int pointLength, ECCurve curve) {

    byte[] x_b = new byte[pointLength / 2];
    byte[] y_b = new byte[pointLength / 2];

    // System.out.println("Serialized Point: " + toHex(serialized_point));
    // src -- This is the source array.
    // srcPos -- This is the starting position in the source array.
    // dest -- This is the destination array.
    // destPos -- This is the starting position in the destination data.
    // length -- This is the number of array elements to be copied.
    System.arraycopy(serialized_point, offset + 1, x_b, 0, pointLength / 2);
    BigInteger x = new BigInteger(bytesToHex(x_b), 16);
    // System.out.println("X:" + toHex(x_b));
    System.arraycopy(serialized_point, offset + (pointLength / 2 + 1), y_b, 0, pointLength / 2);
    BigInteger y = new BigInteger(bytesToHex(y_b), 16);
    // System.out.println("Y:" + toHex(y_b));

    ECPoint point = curve.createPoint(x, y);

    return point;
}
 
Example 3
Source Project: InflatableDonkey   Source File: ECPointsCompact.java    License: MIT License 6 votes vote down vote up
@Deprecated
public static ECPoint decodeFPPoint(ECCurve curve, byte[] data) {
    // Patched org.bouncycastle.math.ec.ECCurve#decodePoint code.
    int expectedLength = (curve.getFieldSize() + 7) / 8;
    if (expectedLength != data.length) {
        throw new IllegalArgumentException("incorrect data length for compact encoding");
    }

    BigInteger X = BigIntegers.fromUnsignedByteArray(data, 0, expectedLength);
    ECPoint p = decompressFPPoint(curve, X);

    if (!satisfiesCofactor(curve, p)) {
        throw new IllegalArgumentException("invalid point");
    }

    return p;
}
 
Example 4
Source Project: InflatableDonkey   Source File: ECPointsCompact.java    License: MIT License 6 votes vote down vote up
@Deprecated
public static ECPoint decompressFPPoint(ECCurve curve, BigInteger X) {
    // See Andrey Jivsov https://www.ietf.org/archive/id/draft-jivsov-ecc-compact-05.txt.
    ECFieldElement x = curve.fromBigInteger(X);
    ECFieldElement rhs = x.square().add(curve.getA()).multiply(x).add(curve.getB());

    // y' = sqrt( C(x) ), where y'>0
    ECFieldElement yTilde = rhs.sqrt();

    if (yTilde == null) {
        throw new IllegalArgumentException("invalid point compression");
    }

    // y = min(y',p-y')
    BigInteger yT = yTilde.toBigInteger();
    BigInteger yTn = yTilde.negate().toBigInteger();
    BigInteger y = yT.compareTo(yTn) == -1 ? yT : yTn;

    // Q=(x,y) is the canonical representation of the point
    ECPoint Q = curve.createPoint(X, y);

    return Q;
}
 
Example 5
Source Project: ID-SDK   Source File: SM2Tool.java    License: Apache License 2.0 5 votes vote down vote up
public SM2Tool() {
	curve = new ECCurve.Fp(p, // q
			a, // a
			b); // b
	G = curve.createPoint(gx, gy);
	ecc_bc_spec = new ECDomainParameters(curve, G, n);
}
 
Example 6
Source Project: gmhelper   Source File: BCECUtil.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * @param xBytes           十六进制形式的公钥x分量,如果是SM2算法,应该是32字节
 * @param yBytes           十六进制形式的公钥y分量,如果是SM2算法,应该是32字节
 * @param curve            EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
 * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
 * @return
 */
public static ECPublicKeyParameters createECPublicKeyParameters(
        byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) {
    final byte uncompressedFlag = 0x04;
    int curveLength = getCurveLength(domainParameters);
    xBytes = fixToCurveLengthBytes(curveLength, xBytes);
    yBytes = fixToCurveLengthBytes(curveLength, yBytes);
    byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
    encodedPubKey[0] = uncompressedFlag;
    System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
    System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
    return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
}
 
Example 7
Source Project: littleca   Source File: BCECUtil.java    License: Apache License 2.0 5 votes vote down vote up
public static ECPublicKeyParameters createEcPublicKey(byte[] xBytes, byte[] yBytes,
                                                      ECCurve curve, ECDomainParameters domainParameters) {
    final byte uncompressedFlag = 0x04;
    byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
    encodedPubKey[0] = uncompressedFlag;
    System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
    System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
    return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
}
 
Example 8
Source Project: alpha-wallet-android   Source File: TrustAddressGenerator.java    License: MIT License 5 votes vote down vote up
private static ECPublicKey decodeKey(byte[] encoded)
        throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
    ECCurve curve = params.getCurve();
    java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
    java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, encoded);
    java.security.spec.ECParameterSpec params2 = EC5Util.convertSpec(ellipticCurve, params);
    java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point, params2);
    return (ECPublicKey) fact.generatePublic(keySpec);
}
 
Example 9
Source Project: org.openhab.ui.habot   Source File: Utils.java    License: Eclipse Public License 1.0 5 votes vote down vote up
/**
 * Load the public key from a URL-safe base64 encoded string. Takes into
 * account the different encodings, including point compression.
 *
 * @param encodedPublicKey
 */
public static PublicKey loadPublicKey(String encodedPublicKey)
        throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] decodedPublicKey = base64Decode(encodedPublicKey);
    KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER_NAME);
    ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(CURVE);
    ECCurve curve = parameterSpec.getCurve();
    ECPoint point = curve.decodePoint(decodedPublicKey);
    ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec);

    return keyFactory.generatePublic(pubSpec);
}
 
Example 10
Source Project: web3sdk   Source File: ECDomainParameters.java    License: Apache License 2.0 5 votes vote down vote up
public ECDomainParameters(ECCurve curve, ECPoint G, BigInteger n, BigInteger h, byte[] seed) {
    this.curve = curve;
    this.G = G.normalize();
    this.n = n;
    this.h = h;
    this.seed = seed;
}
 
Example 11
Source Project: web3sdk   Source File: SM2KeyGenerator.java    License: Apache License 2.0 5 votes vote down vote up
public SM2KeyGenerator() {
    ECCurve curve = new ECCurve.Fp(p, a, b);
    /*
    ECFieldElement x = new Fp(p, gx);
    ECFieldElement y = new Fp(p, gy);
    ECPoint point = new ECPoint.Fp(curve, x, y);
    */
    ECPoint point = curve.createPoint(gx, gy);
    ecdp = new ECDomainParameters(curve, point, n);
}
 
Example 12
Source Project: web3sdk   Source File: ECDSASigner.java    License: Apache License 2.0 5 votes vote down vote up
protected ECFieldElement getDenominator(int coordinateSystem, ECPoint p) {
    switch (coordinateSystem) {
        case ECCurve.COORD_HOMOGENEOUS:
        case ECCurve.COORD_LAMBDA_PROJECTIVE:
        case ECCurve.COORD_SKEWED:
            return p.getZCoord(0);
        case ECCurve.COORD_JACOBIAN:
        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
        case ECCurve.COORD_JACOBIAN_MODIFIED:
            return p.getZCoord(0).square();
        default:
            return null;
    }
}
 
Example 13
Source Project: protools   Source File: SM2.java    License: Apache License 2.0 5 votes vote down vote up
public SM2() {
    curve = new ECCurve.Fp(p, // q
            a, // a
            b); // b
    G = curve.createPoint(gx, gy);
    ecc_bc_spec = new ECDomainParameters(curve, G, n);
}
 
Example 14
Source Project: webpush-java   Source File: Utils.java    License: MIT License 5 votes vote down vote up
/**
 * Load the public key from a byte array. 
 *
 * @param decodedPublicKey
 */
public static PublicKey loadPublicKey(byte[] decodedPublicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
    KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER_NAME);
    ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(CURVE);
    ECCurve curve = parameterSpec.getCurve();
    ECPoint point = curve.decodePoint(decodedPublicKey);
    ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec);

    return keyFactory.generatePublic(pubSpec);
}
 
Example 15
Source Project: jiguang-java-client-common   Source File: BCECUtil.java    License: MIT License 5 votes vote down vote up
public static ECPublicKeyParameters createECPublicKeyParameters(byte[] xBytes, byte[] yBytes,
    ECCurve curve, ECDomainParameters domainParameters) {
    final byte uncompressedFlag = 0x04;
    int curveLength = getCurveLength(domainParameters);
    xBytes = fixToCurveLengthBytes(curveLength, xBytes);
    yBytes = fixToCurveLengthBytes(curveLength, yBytes);
    byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
    encodedPubKey[0] = uncompressedFlag;
    System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
    System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
    return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
}
 
Example 16
Source Project: InflatableDonkey   Source File: RFC6637.java    License: MIT License 5 votes vote down vote up
ECPoint decodePoint(byte[] data) {
    ECCurve curve = ECNamedCurveTable.getByName(curveName).getCurve();
    int compactExportSize = (curve.getFieldSize() + 7) / 8;

    return data.length == compactExportSize
            ? ECPointsCompact.decodeFPPoint(curve, data) // Compact keys support, non RFC6636 compliant.
            : curve.decodePoint(data);
}
 
Example 17
Source Project: xipki   Source File: BaseCertprofile.java    License: Apache License 2.0 5 votes vote down vote up
private static void checkEcSubjectPublicKeyInfo(ASN1ObjectIdentifier curveOid, byte[] encoded)
    throws BadCertTemplateException {
  Args.notNull(curveOid, "curveOid");
  Args.notNull(encoded, "encoded");
  Args.positive(encoded.length, "encoded.length");

  Integer expectedLength = ecCurveFieldSizes.get(curveOid);
  if (expectedLength == null) {
    X9ECParameters ecP = ECUtil.getNamedCurveByOid(curveOid);
    ECCurve curve = ecP.getCurve();
    expectedLength = (curve.getFieldSize() + 7) / 8;
    ecCurveFieldSizes.put(curveOid, expectedLength);
  }

  switch (encoded[0]) {
    case 0x02: // compressed
    case 0x03: // compressed
      if (encoded.length != (expectedLength + 1)) {
        throw new BadCertTemplateException("incorrect length for compressed encoding");
      }
      break;
    case 0x04: // uncompressed
    case 0x06: // hybrid
    case 0x07: // hybrid
      if (encoded.length != (2 * expectedLength + 1)) {
        throw new BadCertTemplateException("incorrect length for uncompressed/hybrid encoding");
      }
      break;
    default:
      throw new BadCertTemplateException(
          String.format("invalid point encoding 0x%02x", encoded[0]));
  }
}
 
Example 18
Source Project: xipki   Source File: PublicKeyChecker.java    License: Apache License 2.0 5 votes vote down vote up
private static void checkECSubjectPublicKeyInfo(ASN1ObjectIdentifier curveOid, byte[] encoded)
    throws BadCertTemplateException {
  Integer expectedLength = EC_CURVEFIELD_SIZES.get(curveOid);
  if (expectedLength == null) {
    X9ECParameters ecP = ECUtil.getNamedCurveByOid(curveOid);
    ECCurve curve = ecP.getCurve();
    expectedLength = (curve.getFieldSize() + 7) / 8;
    EC_CURVEFIELD_SIZES.put(curveOid, expectedLength);
  }

  switch (encoded[0]) {
    case 0x02: // compressed
    case 0x03: // compressed
      if (encoded.length != (expectedLength + 1)) {
        throw new BadCertTemplateException("incorrect length for compressed encoding");
      }
      break;
    case 0x04: // uncompressed
    case 0x06: // hybrid
    case 0x07: // hybrid
      if (encoded.length != (2 * expectedLength + 1)) {
        throw new BadCertTemplateException("incorrect length for uncompressed/hybrid encoding");
      }
      break;
    default:
      throw new BadCertTemplateException(
          "invalid point encoding 0x" + Integer.toString(encoded[0], 16));
  } // end switch
}
 
Example 19
Source Project: aerogear-unifiedpush-server   Source File: KeyUtils.java    License: Apache License 2.0 5 votes vote down vote up
public static PublicKey loadPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] decodedPublicKey = Base64Encoder.decode(publicKey);
    KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);
    ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(CURVE);
    ECCurve curve = parameterSpec.getCurve();
    ECPoint point = curve.decodePoint(decodedPublicKey);
    ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec);

    return keyFactory.generatePublic(pubSpec);

}
 
Example 20
Source Project: javasdk   Source File: ECKey.java    License: GNU Lesser General Public License v3.0 4 votes vote down vote up
/**
 * <p>Given the components of a signature and a selector value, recover and return the public key
 * that generated the signature according to the algorithm in SEC1v2 section 4.1.6.</p>
 * <p>
 * <p>The recId is an index from 0 to 3 which indicates which of the 4 possible keys is the correct one. Because
 * the key recovery operation yields multiple potential keys, the correct key must either be stored alongside the
 * signature, or you must be willing to try each recId in turn until you find one that outputs the key you are
 * expecting.</p>
 * <p>
 * <p>If this method returns null it means recovery was not possible and recId should be iterated.</p>
 * <p>
 * <p>Given the above two points, a correct usage of this method is inside a for loop from 0 to 3, and if the
 * output is null OR a key that is not the one you expect, you try again with the next recId.</p>
 *
 * @param recId       Which possible key to recover.
 * @param sig         the R and S components of the signature, wrapped.
 * @param messageHash Hash of the data that was signed.
 * @return 65-byte encoded public key
 */
public static byte[] recoverPubBytesFromSignature(int recId, ECDSASignature sig, byte[] messageHash) {
    check(recId >= 0, "recId must be positive");
    check(sig.r.signum() >= 0, "r must be positive");
    check(sig.s.signum() >= 0, "s must be positive");
    check(messageHash != null, "messageHash must not be null");
    // 1.0 For j from 0 to h   (h == recId here and the loop is outside this function)
    //   1.1 Let x = r + jn
    BigInteger n = CURVE.getN();  // Curve order.
    BigInteger i = BigInteger.valueOf((long) recId / 2);
    BigInteger x = sig.r.add(i.multiply(n));
    //   1.2. Convert the integer x to an octet string X of length mlen using the conversion routine
    //        specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉.
    //   1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the
    //        conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then
    //        do another iteration of Step 1.
    //
    // More concisely, what these points mean is to use X as a compressed public key.
    ECCurve.Fp curve = (ECCurve.Fp) CURVE.getCurve();
    BigInteger prime = curve.getQ();  // Bouncy Castle is not consistent about the letter it uses for the prime.
    if (x.compareTo(prime) >= 0) {
        // Cannot have point co-ordinates larger than this as everything takes place modulo Q.
        return null;
    }
    // Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities.
    // So it's encoded in the recId.
    ECPoint R = decompressKey(x, (recId & 1) == 1);
    //   1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility).
    if (!R.multiply(n).isInfinity())
        return null;
    //   1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification.
    BigInteger e = new BigInteger(1, messageHash);
    //   1.6. For k from 1 to 2 do the following.   (loop is outside this function via iterating recId)
    //   1.6.1. Compute a candidate public key as:
    //               Q = mi(r) * (sR - eG)
    //
    // Where mi(x) is the modular multiplicative inverse. We transform this into the following:
    //               Q = (mi(r) * s ** R) + (mi(r) * -e ** G)
    // Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
    // ** is point multiplication and + is point addition (the EC group operator).
    //
    // We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive
    // inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.
    BigInteger eInv = BigInteger.ZERO.subtract(e).mod(n);
    BigInteger rInv = sig.r.modInverse(n);
    BigInteger srInv = rInv.multiply(sig.s).mod(n);
    BigInteger eInvrInv = rInv.multiply(eInv).mod(n);
    ECPoint.Fp q = (ECPoint.Fp) ECAlgorithms.sumOfTwoMultiplies(CURVE.getG(), eInvrInv, R, srInv);
    return q.getEncoded(/* compressed */ false);
}
 
Example 21
Source Project: littleca   Source File: BCECUtil.java    License: Apache License 2.0 4 votes vote down vote up
public static ECPublicKeyParameters createEcPublicKey(BigInteger x, BigInteger y,
                                                      ECCurve curve, ECDomainParameters domainParameters) {
    byte[] xBytes = x.toByteArray();
    byte[] yBytes = y.toByteArray();
    return createEcPublicKey(xBytes, yBytes, curve, domainParameters);
}
 
Example 22
Source Project: littleca   Source File: BCECUtil.java    License: Apache License 2.0 4 votes vote down vote up
public static ECPublicKeyParameters createEcPublicKey(String xHex, String yHex,
                                                      ECCurve curve, ECDomainParameters domainParameters) {
    byte[] xBytes = ByteUtils.fromHexString(xHex);
    byte[] yBytes = ByteUtils.fromHexString(yHex);
    return createEcPublicKey(xBytes, yBytes, curve, domainParameters);
}
 
Example 23
Source Project: julongchain   Source File: SM2.java    License: Apache License 2.0 4 votes vote down vote up
public SM2() {
    curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B);
    ECPoint ecc_point_g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY);
    ecc_bc_spec = new ECDomainParameters(curve, ecc_point_g, SM2_ECC_N);
}
 
Example 24
Source Project: nuls-v2   Source File: LazyECPoint.java    License: MIT License 4 votes vote down vote up
public LazyECPoint(ECCurve curve, byte[] bits) {
    this.curve = curve;
    this.bits = bits;
}
 
Example 25
Source Project: nuls-v2   Source File: LazyECPoint.java    License: MIT License 4 votes vote down vote up
public ECCurve getCurve() {
    return get().getCurve();
}
 
Example 26
Source Project: jingtum-lib-java   Source File: SECP256K1.java    License: MIT License 4 votes vote down vote up
public static ECCurve curve() {
	return ecParams.getCurve();
}
 
Example 27
Source Project: web3sdk   Source File: ECDomainParameters.java    License: Apache License 2.0 4 votes vote down vote up
public ECDomainParameters(ECCurve curve, ECPoint G, BigInteger n) {
    this(curve, G, n, ONE, null);
}
 
Example 28
Source Project: web3sdk   Source File: ECDomainParameters.java    License: Apache License 2.0 4 votes vote down vote up
public ECDomainParameters(ECCurve curve, ECPoint G, BigInteger n, BigInteger h) {
    this(curve, G, n, h, null);
}
 
Example 29
Source Project: web3sdk   Source File: ECDomainParameters.java    License: Apache License 2.0 4 votes vote down vote up
public ECCurve getCurve() {
    return curve;
}
 
Example 30
Source Project: web3sdk   Source File: ECDSASigner.java    License: Apache License 2.0 4 votes vote down vote up
/**
 * return true if the value r and s represent a DSA signature for the passed in message (for
 * standard DSA the message should be a SHA-1 hash of the real message to be verified).
 */
@Override
public boolean verifySignature(byte[] message, BigInteger r, BigInteger s) {
    ECDomainParameters ec = key.getParameters();
    BigInteger n = ec.getN();
    BigInteger e = calculateE(n, message);

    // r in the range [1,n-1]
    if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) {
        return false;
    }

    // s in the range [1,n-1]
    if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) {
        return false;
    }

    BigInteger c = s.modInverse(n);

    BigInteger u1 = e.multiply(c).mod(n);
    BigInteger u2 = r.multiply(c).mod(n);

    ECPoint G = ec.getG();
    ECPoint Q = ((ECPublicKeyParameters) key).getQ();

    ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);

    // components must be bogus.
    if (point.isInfinity()) {
        return false;
    }

    /*
     * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
     *
     * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
     * If the cofactor is known and small, we generate those possible field values and project each
     * of them to the same "denominator" (depending on the particular projective coordinates in use)
     * as the calculated point.X. If any of the projected values matches point.X, then we have:
     *     (point.X / Denominator mod p) mod n == r
     * as required, and verification succeeds.
     *
     * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
     * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
     */
    ECCurve curve = point.getCurve();
    if (curve != null) {
        BigInteger cofactor = curve.getCofactor();
        if (cofactor != null && cofactor.compareTo(EIGHT) <= 0) {
            ECFieldElement D = getDenominator(curve.getCoordinateSystem(), point);
            if (D != null && !D.isZero()) {
                ECFieldElement X = point.getXCoord();
                while (curve.isValidFieldElement(r)) {
                    ECFieldElement R = curve.fromBigInteger(r).multiply(D);
                    if (R.equals(X)) {
                        return true;
                    }
                    r = r.add(n);
                }
                return false;
            }
        }
    }

    BigInteger v = point.normalize().getAffineXCoord().toBigInteger().mod(n);
    return v.equals(r);
}