private static void addNamedCurves_jdk18on() {
    final Class<?>[] Param_CurveDB_add =
        new Class[] {
          String.class,
          String.class,
          int.class,
          String.class,
          String.class,
          String.class,
          String.class,
          String.class,
          String.class,
          int.class,
          Pattern.class
        };
    final Class<?>[] Param_getCurve = new Class[] {String.class};

    Method method_add = getMethod(class_CurveDB, "add", Param_CurveDB_add);
    if (method_add == null) {
      return;
    }

    Method method_getCurve = getMethod(class_CurveDB, "lookup", Param_getCurve);
    if (method_getCurve == null) {
      return;
    }

    Field field_oidMap = getField(class_CurveDB, "oidMap");
    if (field_oidMap == null) {
      return;
    }

    Field field_specCollection = getField(class_CurveDB, "specCollection");
    if (field_specCollection == null) {
      return;
    }

    Set<String> processedCurveOids = new HashSet<>();
    Map<String, String> addedCurves = new HashMap<>();

    Enumeration<?> curveNames = ECNamedCurveTable.getNames();
    while (curveNames.hasMoreElements()) {
      String curveName = (String) curveNames.nextElement();
      ASN1ObjectIdentifier curveId = getCurveId(curveName);
      if (curveId == null) {
        LOG.debug("cound not find curve OID for curve {}, ignore it", curveName);
        continue;
      }

      String curveDesc = "named curve " + curveName + " (" + curveId + ")";

      if (processedCurveOids.contains(curveId.getId())) {
        LOG.debug("{} is already processed, ignore it", curveDesc);
        continue;
      }

      processedCurveOids.add(curveId.getId());

      if (curve_isRegistered(method_getCurve, curveId)) {
        LOG.info("{} is already registered, ignore it", curveDesc);
        continue;
      }

      X9ECParameters params = ECNamedCurveTable.getByOID(curveId);
      ECCurve curve = params.getCurve();
      if (curve instanceof ECCurve.Fp || curve instanceof ECCurve.F2m) {
        CurveData c = new CurveData(params);
        boolean added =
            CurveDB_add(
                method_add,
                curveName,
                curveId.getId(),
                c.type,
                c.sfield,
                c.a,
                c.b,
                c.x,
                c.y,
                c.n,
                c.h);

        if (added) {
          LOG.debug("added {}", curveDesc);
          addedCurves.put(curveName, curveId.getId());
        } else {
          LOG.warn("could not add {}", curveDesc);
        }
      } else {
        LOG.info("unknown curve type {}", curve.getClass().getName());
      }
    }

    try {
      Map<?, ?> oidMap = (Map<?, ?>) field_oidMap.get(null);
      Collection<?> namedCurves = Collections.unmodifiableCollection(oidMap.values());

      field_specCollection.set(null, namedCurves);
    } catch (IllegalArgumentException | IllegalAccessException | ClassCastException e) {
      final String message = "could not update change the value of field CurveDB.specCollection.";
      if (LOG.isWarnEnabled()) {
        LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
      }
      LOG.debug(message, e);
    }

    logAddedCurves(addedCurves);
  }
  /**
   * Create a public key from the passed in SubjectPublicKeyInfo
   *
   * @param keyInfo the SubjectPublicKeyInfo containing the key data
   * @return the appropriate key parameter
   * @throws IOException on an error decoding the key
   */
  public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException {
    AlgorithmIdentifier algId = keyInfo.getAlgorithm();

    if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)
        || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa)) {
      RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());

      return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
    } else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber)) {
      DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());

      BigInteger y = dhPublicKey.getY().getValue();

      DHDomainParameters dhParams = DHDomainParameters.getInstance(algId.getParameters());

      BigInteger p = dhParams.getP().getValue();
      BigInteger g = dhParams.getG().getValue();
      BigInteger q = dhParams.getQ().getValue();

      BigInteger j = null;
      if (dhParams.getJ() != null) {
        j = dhParams.getJ().getValue();
      }

      DHValidationParameters validation = null;
      DHValidationParms dhValidationParms = dhParams.getValidationParms();
      if (dhValidationParms != null) {
        byte[] seed = dhValidationParms.getSeed().getBytes();
        BigInteger pgenCounter = dhValidationParms.getPgenCounter().getValue();

        // TODO Check pgenCounter size?

        validation = new DHValidationParameters(seed, pgenCounter.intValue());
      }

      return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
    } else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) {
      DHParameter params = DHParameter.getInstance(algId.getParameters());
      ASN1Integer derY = (ASN1Integer) keyInfo.parsePublicKey();

      BigInteger lVal = params.getL();
      int l = lVal == null ? 0 : lVal.intValue();
      DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);

      return new DHPublicKeyParameters(derY.getValue(), dhParams);
    }
    // BEGIN android-removed
    // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
    // {
    //     ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
    //     ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
    //
    //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
    //         params.getP(), params.getG()));
    // }
    // END android-removed
    else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
        || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1)) {
      ASN1Integer derY = (ASN1Integer) keyInfo.parsePublicKey();
      ASN1Encodable de = algId.getParameters();

      DSAParameters parameters = null;
      if (de != null) {
        DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
        parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
      }

      return new DSAPublicKeyParameters(derY.getValue(), parameters);
    } else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)) {
      X962Parameters params = X962Parameters.getInstance(algId.getParameters());

      X9ECParameters x9;
      if (params.isNamedCurve()) {
        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) params.getParameters();
        x9 = ECNamedCurveTable.getByOID(oid);
      } else {
        x9 = X9ECParameters.getInstance(params.getParameters());
      }

      ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
      X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key);

      // TODO We lose any named parameters here

      ECDomainParameters dParams =
          new ECDomainParameters(x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());

      return new ECPublicKeyParameters(derQ.getPoint(), dParams);
    } else {
      throw new RuntimeException("algorithm identifier in key not recognised");
    }
  }
  private static void addNamedCurves_jdk17() {
    final Class<?>[] Param_NamedCurve_add =
        new Class[] {
          String.class,
          String.class,
          int.class,
          String.class,
          String.class,
          String.class,
          String.class,
          String.class,
          String.class,
          int.class
        };
    final Class<?>[] Param_getCurve = new Class[] {String.class};

    Method method_add = getMethod(class_NamedCurve, "add", Param_NamedCurve_add);
    if (method_add == null) {
      return;
    }

    Method method_getCurve = getMethod(class_NamedCurve, "getECParameterSpec", Param_getCurve);
    if (method_getCurve == null) {
      return;
    }

    Field field_SPLIT_PATTERN = getField(class_NamedCurve, "SPLIT_PATTERN");
    if (field_SPLIT_PATTERN == null) {
      return;
    }

    try {
      field_SPLIT_PATTERN.set(null, SPLIT_PATTERN);
    } catch (IllegalArgumentException | IllegalAccessException e) {
      final String message = "could not set Field SPLIT_PATTERN";
      if (LOG.isWarnEnabled()) {
        LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
      }
      LOG.debug(message, e);
      return;
    }

    Set<String> processedCurveOids = new HashSet<>();
    Map<String, String> addedCurves = new HashMap<>();

    Enumeration<?> curveNames = ECNamedCurveTable.getNames();
    while (curveNames.hasMoreElements()) {
      String curveName = (String) curveNames.nextElement();
      ASN1ObjectIdentifier curveId = getCurveId(curveName);

      if (curveId == null) {
        LOG.info("cound not find curve OID for curve {}, ignore it", curveName);
        continue;
      }

      String curveDesc = "named curve " + curveName + " (" + curveId + ")";

      if (processedCurveOids.contains(curveId.getId())) {
        LOG.debug("{} is already processed, ignore it", curveDesc);
        continue;
      }

      processedCurveOids.add(curveId.getId());

      if (curve_isRegistered(method_getCurve, curveId)) {
        LOG.debug("{} is already registered, ignore it", curveDesc);
        continue;
      }

      X9ECParameters params = ECNamedCurveTable.getByOID(curveId);
      ECCurve curve = params.getCurve();

      if (curve instanceof ECCurve.Fp || curve instanceof ECCurve.F2m) {
        CurveData c = new CurveData(params);
        boolean added =
            NamedCurve_add(
                method_add,
                curveName,
                curveId.getId(),
                c.type,
                c.sfield,
                c.a,
                c.b,
                c.x,
                c.y,
                c.n,
                c.h);

        if (added) {
          LOG.debug("added {}", curveDesc);
          addedCurves.put(curveName, curveId.getId());
        } else {
          LOG.warn("could not add {}", curveDesc);
        }
      } else {
        LOG.info("unknown curve type {}", curve.getClass().getName());
      }
    }

    try {
      field_SPLIT_PATTERN.set(null, null);
    } catch (IllegalArgumentException | IllegalAccessException e) {
      final String message = "could not set Field SPLIT_PATTERN";
      if (LOG.isWarnEnabled()) {
        LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
      }
      LOG.debug(message, e);
      return;
    }

    logAddedCurves(addedCurves);
  }