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_Point 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)) {
65 return egsr->to_legacy_point();
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());
84 for(uint8_t v = 0; v != 4; ++v) {
86 EC_Point R = recover_ecdsa_public_key(this->
domain(), msg, r, s, v);
96 throw Internal_Error(
"Could not determine ECDSA recovery parameter");
123 PK_Ops::Signature_with_Hash(padding),
124 m_group(ecdsa.domain()),
125 m_x(ecdsa._private_key()),
127 m_b_inv(m_b.invert()) {
128#if defined(BOTAN_HAS_RFC6979_GENERATOR)
129 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
130 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa.
_private_key());
134 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
136 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng)
override;
138 AlgorithmIdentifier algorithm_identifier()
const override;
141 const EC_Group m_group;
144#if defined(BOTAN_HAS_RFC6979_GENERATOR)
145 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
148 std::vector<BigInt> m_ws;
154AlgorithmIdentifier ECDSA_Signature_Operation::algorithm_identifier()
const {
155 const std::string full_name =
"ECDSA/" + hash_function();
156 const OID oid = OID::from_string(full_name);
157 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
160std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
161 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
163#if defined(BOTAN_HAS_RFC6979_GENERATOR)
164 const auto k = m_rfc6979->nonce_for(m_group, m);
166 const auto k = EC_Scalar::random(m_group, rng);
169 const auto r = EC_Scalar::gk_x_mod_order(k, rng, m_ws);
172 const auto k_inv = (m_b * k).invert() * m_b;
180 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
182 const auto s = (k_inv * xr_m) * m_b_inv;
185 if(r.is_zero() || s.is_zero()) {
186 throw Internal_Error(
"During ECDSA signature generated zero r/s");
189 return EC_Scalar::serialize_pair(r, s);
195class ECDSA_Verification_Operation
final :
public PK_Ops::Verification_with_Hash {
197 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa, std::string_view padding) :
198 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_key()) {}
200 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa,
const AlgorithmIdentifier& alg_id) :
201 PK_Ops::Verification_with_Hash(alg_id,
"ECDSA", true),
202 m_group(ecdsa.domain()),
203 m_gy_mul(ecdsa._public_key()) {}
205 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig)
override;
208 const EC_Group m_group;
209 const EC_Group::Mul2Table m_gy_mul;
212bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
213 if(
auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
214 const auto& [r, s] = rs.value();
216 if(r.is_nonzero() && s.is_nonzero()) {
217 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
219 const auto w = s.invert();
232 std::string_view provider)
const {
233 if(provider ==
"base" || provider.empty()) {
234 return std::make_unique<ECDSA_Verification_Operation>(*
this, params);
242 if(provider ==
"base" || provider.empty()) {
243 return std::make_unique<ECDSA_Verification_Operation>(*
this, signature_algorithm);
250 std::string_view params,
251 std::string_view provider)
const {
252 if(provider ==
"base" || provider.empty()) {
253 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)
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_Point & public_point() const
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
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)