11#include <botan/ecdsa.h>
13#include <botan/internal/keypair.h>
14#include <botan/internal/pk_ops_impl.h>
16#if defined(BOTAN_HAS_RFC6979_GENERATOR)
17 #include <botan/internal/rfc6979.h>
24EC_AffinePoint recover_ecdsa_public_key(
25 const EC_Group& group,
const std::vector<uint8_t>& msg,
const BigInt& r,
const BigInt& s, uint8_t v) {
26 if(group.has_cofactor()) {
27 throw Invalid_Argument(
"ECDSA public key recovery only supported for prime order groups");
31 throw Invalid_Argument(
"Unexpected v param for ECDSA public key recovery");
34 const BigInt& group_order = group.get_order();
36 if(r <= 0 || r >= group_order || s <= 0 || s >= group_order) {
37 throw Invalid_Argument(
"Out of range r/s cannot recover ECDSA public key");
40 const uint8_t y_odd = v % 2;
41 const uint8_t add_order = v >> 1;
42 const size_t p_bytes = group.get_p_bytes();
50 if(x.bytes() <= p_bytes) {
51 std::vector<uint8_t>
X(p_bytes + 1);
54 x.serialize_to(std::span{
X}.subspan(1));
63 EC_Group::Mul2Table GR_mul(R.value());
64 if(
auto egsr = GR_mul.mul2_vartime(ne * r_inv, ss * r_inv)) {
70 throw Decoding_Error(
"Failed to recover ECDSA public key from signature/msg pair");
76 const EC_Group& group,
const std::vector<uint8_t>& msg,
const BigInt& r,
const BigInt& s, uint8_t v) :
77 EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {}
80 return std::make_unique<ECDSA_PrivateKey>(rng,
domain());
86 for(uint8_t v = 0; v != 4; ++v) {
88 const auto R = recover_ecdsa_public_key(this->
domain(), msg, r, s, v);
90 if(R.serialize_compressed() == this_key) {
98 throw Internal_Error(
"Could not determine ECDSA recovery parameter");
125 PK_Ops::Signature_with_Hash(padding),
126 m_group(ecdsa.domain()),
127 m_x(ecdsa._private_key()),
129 m_b_inv(m_b.invert()) {
130#if defined(BOTAN_HAS_RFC6979_GENERATOR)
131 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
132 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa.
_private_key());
136 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
138 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng)
override;
140 AlgorithmIdentifier algorithm_identifier()
const override;
143 const EC_Group m_group;
146#if defined(BOTAN_HAS_RFC6979_GENERATOR)
147 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
150 std::vector<BigInt> m_ws;
156AlgorithmIdentifier ECDSA_Signature_Operation::algorithm_identifier()
const {
157 const std::string full_name =
"ECDSA/" + hash_function();
158 const OID oid = OID::from_string(full_name);
159 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
162std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
163 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
165#if defined(BOTAN_HAS_RFC6979_GENERATOR)
166 const auto k = m_rfc6979->nonce_for(m_group, m);
168 const auto k = EC_Scalar::random(m_group, rng);
171 const auto r = EC_Scalar::gk_x_mod_order(k, rng, m_ws);
174 const auto k_inv = (m_b * k).invert() * m_b;
182 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
184 const auto s = (k_inv * xr_m) * m_b_inv;
187 if(r.is_zero() || s.is_zero()) {
188 throw Internal_Error(
"During ECDSA signature generated zero r/s");
191 return EC_Scalar::serialize_pair(r, s);
197class ECDSA_Verification_Operation
final :
public PK_Ops::Verification_with_Hash {
199 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa, std::string_view padding) :
200 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_ec_point()) {}
202 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa,
const AlgorithmIdentifier& alg_id) :
203 PK_Ops::Verification_with_Hash(alg_id,
"ECDSA", true),
204 m_group(ecdsa.domain()),
205 m_gy_mul(ecdsa._public_ec_point()) {}
207 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig)
override;
210 const EC_Group m_group;
211 const EC_Group::Mul2Table m_gy_mul;
214bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
215 if(
auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
216 const auto& [r, s] = rs.value();
218 if(r.is_nonzero() && s.is_nonzero()) {
219 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
221 const auto w = s.invert_vartime();
234 std::string_view provider)
const {
235 if(provider ==
"base" || provider.empty()) {
236 return std::make_unique<ECDSA_Verification_Operation>(*
this, params);
244 if(provider ==
"base" || provider.empty()) {
245 return std::make_unique<ECDSA_Verification_Operation>(*
this, signature_algorithm);
252 std::string_view params,
253 std::string_view provider)
const {
254 if(provider ==
"base" || provider.empty()) {
255 return std::make_unique<ECDSA_Signature_Operation>(*
this, params, rng);
std::unique_ptr< Public_Key > public_key() const override
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
bool check_key(RandomNumberGenerator &rng, bool) const override
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
ECDSA_PublicKey()=default
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const override
uint8_t recovery_param(const std::vector< uint8_t > &msg, const BigInt &r, const BigInt &s) const
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
T serialize_compressed() const
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
const EC_Scalar & _private_key() const
bool check_key(RandomNumberGenerator &rng, bool strong) const override
const EC_Group & domain() const
const EC_AffinePoint & _public_ec_point() const
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
EC_Scalar invert_vartime() const
static EC_Scalar from_bytes_with_trunc(const EC_Group &group, std::span< const uint8_t > bytes)
int(* final)(unsigned char *, CTX *)
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)