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>
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");
34 const BigInt& group_order = group.get_order();
36 if(r <= 0 || r >= group_order || s <= 0 || s >= group_order) {
40 const uint8_t y_odd = v % 2;
41 const bool add_order = (v >> 1) == 0x01;
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));
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;
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);
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_ec_point()) {}
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_ec_point()) {}
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_vartime();
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 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
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
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)