11#include <botan/ecdsa.h>
13#include <botan/ec_group.h>
14#include <botan/internal/keypair.h>
15#include <botan/internal/pk_ops_impl.h>
17#if defined(BOTAN_HAS_RFC6979_GENERATOR)
18 #include <botan/internal/rfc6979.h>
26 const EC_Group& group,
const std::vector<uint8_t>& msg,
const BigInt& r,
const BigInt& s, uint8_t v) {
27 if(group.has_cofactor()) {
28 throw Invalid_Argument(
"ECDSA public key recovery only supported for prime order groups");
35 const BigInt& group_order = group.get_order();
37 if(r <= 0 || r >= group_order || s <= 0 || s >= group_order) {
41 const uint8_t y_odd = v % 2;
42 const bool add_order = (v >> 1) == 0x01;
43 const size_t p_bytes = group.get_p_bytes();
51 if(x.bytes() <= p_bytes) {
52 std::vector<uint8_t> X(p_bytes + 1);
55 x.serialize_to(std::span{X}.subspan(1));
65 if(
auto egsr = GR_mul.mul2_vartime(ne * r_inv, ss * r_inv)) {
71 throw Decoding_Error(
"Failed to recover ECDSA public key from signature/msg pair");
77 const EC_Group& group,
const std::vector<uint8_t>& msg,
const BigInt& r,
const BigInt& s, uint8_t v) :
78 EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {}
85 return std::make_unique<ECDSA_PrivateKey>(rng,
domain());
91 for(uint8_t v = 0; v != 4; ++v) {
93 const auto R = recover_ecdsa_public_key(this->
domain(), msg, r, s, v);
95 if(R.serialize_compressed() == this_key) {
103 throw Internal_Error(
"Could not determine ECDSA recovery parameter");
130 PK_Ops::Signature_with_Hash(padding),
131 m_group(ecdsa.domain()),
132 m_x(ecdsa._private_key()),
134#if defined(BOTAN_HAS_RFC6979_GENERATOR)
135 m_rfc6979 = std::make_unique<RFC6979_Nonce_Generator>(
136 this->rfc6979_hash_function(), m_group.get_order_bits(), ecdsa.
_private_key());
140 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
142 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng)
override;
144 AlgorithmIdentifier algorithm_identifier()
const override;
147 const EC_Group m_group;
150#if defined(BOTAN_HAS_RFC6979_GENERATOR)
151 std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
158 const std::string full_name =
"ECDSA/" + hash_function();
159 const OID oid = OID::from_string(full_name);
160 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
163std::vector<uint8_t> ECDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
164 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
166#if defined(BOTAN_HAS_RFC6979_GENERATOR)
167 const auto k = m_rfc6979->nonce_for(m_group, m);
169 const auto k = EC_Scalar::random(m_group, rng);
172 const auto r = EC_Scalar::gk_x_mod_order(k, rng);
193 const auto k_inv = (m_b * k).invert();
195 const auto xr_m = ((m_x * m_b) * r) + (m * m_b);
197 const auto s = (k_inv * xr_m);
203 if(r.is_zero() || s.is_zero()) {
204 throw Internal_Error(
"During ECDSA signature generated zero r/s");
207 return EC_Scalar::serialize_pair(r, s);
213class ECDSA_Verification_Operation final :
public PK_Ops::Verification_with_Hash {
215 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa, std::string_view padding) :
216 PK_Ops::Verification_with_Hash(padding), m_group(ecdsa.domain()), m_gy_mul(ecdsa._public_ec_point()) {}
218 ECDSA_Verification_Operation(
const ECDSA_PublicKey& ecdsa,
const AlgorithmIdentifier& alg_id) :
219 PK_Ops::Verification_with_Hash(alg_id,
"ECDSA", true),
220 m_group(ecdsa.domain()),
221 m_gy_mul(ecdsa._public_ec_point()) {}
223 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig)
override;
226 const EC_Group m_group;
227 const EC_Group::Mul2Table m_gy_mul;
230bool ECDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
231 if(
auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
232 const auto& [r, s] = rs.value();
234 if(r.is_nonzero() && s.is_nonzero()) {
235 const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
237 const auto w = s.invert_vartime();
250 std::string_view provider)
const {
251 if(provider ==
"base" || provider.empty()) {
252 return std::make_unique<ECDSA_Verification_Operation>(*
this, params);
260 if(provider ==
"base" || provider.empty()) {
261 return std::make_unique<ECDSA_Verification_Operation>(*
this, signature_algorithm);
268 std::string_view params,
269 std::string_view provider)
const {
270 if(provider ==
"base" || provider.empty()) {
271 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 strong) const override
std::string algo_name() 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
std::optional< size_t > _signature_element_size_for_DER_encoding() const override
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
T serialize_compressed() const
Table for computing g*x + h*y.
bool mul2_vartime_x_mod_order_eq(const EC_Scalar &v, const EC_Scalar &x, const EC_Scalar &y) const
size_t get_order_bytes() const
const EC_Scalar & _private_key() const
bool check_key(RandomNumberGenerator &rng, bool strong) const override
const EC_Group & domain() const
EC_PublicKey(const EC_PublicKey &other)=default
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)
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)