UltrafastSecp256k1 3.68.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
ecdsa.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_ECDSA_HPP
2#define SECP256K1_ECDSA_HPP
3#pragma once
4
5// ============================================================================
6// ECDSA Sign / Verify for secp256k1
7// ============================================================================
8// Standard ECDSA (RFC 6979 deterministic nonce recommended for production).
9// This implementation provides:
10// - sign(message_hash, private_key) -> (r, s)
11// - verify(message_hash, public_key, r, s) -> bool
12// - Signature normalization (low-S, BIP-62)
13//
14// WARNING: The nonce k MUST be cryptographically random or deterministic
15// (RFC 6979). Reusing k leaks the private key. This library provides a
16// deterministic nonce function (RFC 6979) for safety.
17// ============================================================================
18
19#include <array>
20#include <cstdint>
21#include "secp256k1/scalar.hpp"
22#include "secp256k1/point.hpp"
23
24namespace secp256k1 {
25
26// -- Signature ----------------------------------------------------------------
27
31
32 // DER encoding (variable length, max 72 bytes)
33 // Returns {encoded_bytes, length}
34 std::pair<std::array<std::uint8_t, 72>, std::size_t> to_der() const;
35
36 // Compact 64-byte encoding: r (32 bytes) || s (32 bytes)
37 std::array<std::uint8_t, 64> to_compact() const;
38
39 // Decode from compact 64-byte encoding
40 static ECDSASignature from_compact(const std::uint8_t* data64);
41 static ECDSASignature from_compact(const std::array<std::uint8_t, 64>& data);
42
43 // Strict compact parse: rejects r >= n, s >= n, r == 0, s == 0 (no reduce)
44 static bool parse_compact_strict(const std::uint8_t* data64, ECDSASignature& out) noexcept;
45 static bool parse_compact_strict(const std::array<std::uint8_t, 64>& data, ECDSASignature& out) noexcept;
46
47 // Normalize to low-S form (BIP-62): if s > n/2, replace with n - s
49
50 // Check if signature has low-S
51 bool is_low_s() const;
52
53 // C5: explicit validity predicate — propagates signing success/failure
54 // across the CT→ABI boundary without relying on implicit zero-detection.
55 // A valid ECDSA signature always satisfies r ∈ [1, n-1] and s ∈ [1, n-1].
56 // CT signing returns a zero (r,s) on any degenerate case (k≡0 mod n, etc.).
57 bool is_valid() const noexcept { return !r.is_zero() && !s.is_zero(); }
58};
59
60// -- ECDSA Operations ---------------------------------------------------------
61
62// Sign a 32-byte message hash with a private key (FAST, non-constant-time).
63// Uses RFC 6979 deterministic nonce generation, variable-time R=k*G.
64// For production signing where private_key/nonce must be secret:
65// use secp256k1::ct::ecdsa_sign() from <secp256k1/ct/sign.hpp>.
66// Returns normalized (low-S) signature.
67// Returns {zero, zero} signature on failure (zero key, etc.)
68ECDSASignature ecdsa_sign(const std::array<std::uint8_t, 32>& msg_hash,
69 const fast::Scalar& private_key);
70
71// Sign + verify (FIPS 186-4 fault attack countermeasure).
72// Verifies the produced signature before returning it.
73// Use this when fault injection resistance is required.
74ECDSASignature ecdsa_sign_verified(const std::array<std::uint8_t, 32>& msg_hash,
75 const fast::Scalar& private_key);
76
77// Sign with hedged nonce: RFC 6979 + extra entropy (RFC 6979 Section 3.6).
78// aux_rand: 32 bytes of fresh CSPRNG randomness mixed into the HMAC-DRBG.
79// This provides defense-in-depth against HMAC-SHA256 weakness or fault
80// injection while maintaining deterministic fallback behavior.
81// The nonce is deterministic for a given (key, msg, aux_rand) triple.
82// Equivalent to libsecp256k1's secp256k1_ecdsa_sign() with ndata parameter.
83ECDSASignature ecdsa_sign_hedged(const std::array<std::uint8_t, 32>& msg_hash,
84 const fast::Scalar& private_key,
85 const std::array<std::uint8_t, 32>& aux_rand);
86
87// Hedged sign + verify (FIPS 186-4 fault attack countermeasure).
88ECDSASignature ecdsa_sign_hedged_verified(const std::array<std::uint8_t, 32>& msg_hash,
89 const fast::Scalar& private_key,
90 const std::array<std::uint8_t, 32>& aux_rand);
91
92// Verify an ECDSA signature against a public key and message hash.
93// Accepts both low-S and high-S signatures.
94// Raw-pointer overload: avoids 32B array copy when caller has a raw pointer.
95bool ecdsa_verify(const std::uint8_t* msg_hash32,
96 const fast::Point& public_key,
97 const ECDSASignature& sig);
98
99// Array overload: thin wrapper.
100bool ecdsa_verify(const std::array<std::uint8_t, 32>& msg_hash,
101 const fast::Point& public_key,
102 const ECDSASignature& sig);
103
104// -- RFC 6979 Deterministic Nonce ---------------------------------------------
105
106// Generate deterministic nonce k per RFC 6979.
107// Inputs: private key (32 bytes), message hash (32 bytes).
108// Output: scalar k suitable for ECDSA signing.
110 const std::array<std::uint8_t, 32>& msg_hash);
111
112// Hedged variant: RFC 6979 Section 3.6 with extra entropy.
113// aux_rand (32 bytes of CSPRNG randomness) is mixed into the HMAC-DRBG.
115 const std::array<std::uint8_t, 32>& msg_hash,
116 const std::array<std::uint8_t, 32>& aux_rand);
117
118} // namespace secp256k1
119
120#endif // SECP256K1_ECDSA_HPP
bool is_zero() const noexcept
ECDSASignature ecdsa_sign_verified(const std::array< std::uint8_t, 32 > &msg_hash, const fast::Scalar &private_key)
fast::Scalar rfc6979_nonce(const fast::Scalar &private_key, const std::array< std::uint8_t, 32 > &msg_hash)
fast::Scalar rfc6979_nonce_hedged(const fast::Scalar &private_key, const std::array< std::uint8_t, 32 > &msg_hash, const std::array< std::uint8_t, 32 > &aux_rand)
ECDSASignature ecdsa_sign_hedged(const std::array< std::uint8_t, 32 > &msg_hash, const fast::Scalar &private_key, const std::array< std::uint8_t, 32 > &aux_rand)
ECDSASignature ecdsa_sign(const std::array< std::uint8_t, 32 > &msg_hash, const fast::Scalar &private_key)
bool ecdsa_verify(const std::uint8_t *msg_hash32, const fast::Point &public_key, const ECDSASignature &sig)
ECDSASignature ecdsa_sign_hedged_verified(const std::array< std::uint8_t, 32 > &msg_hash, const fast::Scalar &private_key, const std::array< std::uint8_t, 32 > &aux_rand)
bool is_valid() const noexcept
Definition ecdsa.hpp:57
static ECDSASignature from_compact(const std::array< std::uint8_t, 64 > &data)
std::pair< std::array< std::uint8_t, 72 >, std::size_t > to_der() const
ECDSASignature normalize() const
static bool parse_compact_strict(const std::uint8_t *data64, ECDSASignature &out) noexcept
static bool parse_compact_strict(const std::array< std::uint8_t, 64 > &data, ECDSASignature &out) noexcept
std::array< std::uint8_t, 64 > to_compact() const
static ECDSASignature from_compact(const std::uint8_t *data64)