Bouncy Castle — это сразу две вещи: провайдер JCA (BC), который подключается к Signature, KeyPairGenerator и KEM, и легковесные API, например ECDSASigner, работающие без JCA. bcpkix добавляет сертификаты, CMS, OCSP и PEMParser, которого до сих пор нет в JDK. Большая часть кода на JVM, работающего с secp256k1, Brainpool, PGP или сертификатами, зависит от Bouncy Castle.
Параметры ECDSA по умолчанию совпадают с JDK: SHA256withECDSA выдаёт DER со случайным nonce и не нормализует s, а проверка принимает s из обеих половин диапазона. Отличия включаются явно, через имена алгоритмов. SHA256withPLAIN-ECDSA выдаёт 64-байтовую подпись raw r‖s, которую ожидает JWS; SHA256withECDDSA подписывает детерминированно, а легковесный ECDSASigner с HMacDSAKCalculator в точности воспроизвёл тестовый вектор RFC 6979. Как и в SunEC, подпись raw, переданная алгоритму для DER, приводит к исключению SignatureException, а не к возврату false.
Большинство приходит сюда ради поддержки кривых: на кривых от P-224 до P-521, secp256k1 и Brainpool r1, а также с Ed25519 и Ed448 подпись и проверка прошли успешно. Зарегистрируйте провайдер и укажите его по имени (KeyPairGenerator.getInstance("EC", "BC")): иначе первым будет опрошен SunEC из JDK, который отклоняет secp256k1, а пример именно так этого и избегает.
Поддержка постквантовых алгоритмов в версии 1.86 — самая широкая среди проверенных библиотек: ML-KEM через javax.crypto.KEM, ML-DSA, SLH-DSA и LMS в провайдере BC, а также Falcon и XMSS в BCPQC. Попробуйте алгоритмы в песочнице постквантовых подписей, а гибридные сертификаты разберите инспектором постквантовых сертификатов.
JcaPEMWriter записывает закрытые ключи EC в формате SEC1 -----BEGIN EC PRIVATE KEY-----, а PEMParser читает их обратно как PEMKeyPair; для инструментов, которые ожидают PKCS#8, ключ сначала нужно преобразовать. Если перепутаны подписи PLAIN и DER, поможет конвертер DER ⇄ raw.