UltrafastSecp256k1 3.68.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
private_key.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_PRIVATE_KEY_HPP
2#define SECP256K1_PRIVATE_KEY_HPP
3#pragma once
4
5// ============================================================================
6// PrivateKey -- Strong Type for Secret Key Material
7// ============================================================================
8// Wraps fast::Scalar with:
9// - No implicit conversion to Scalar (prevents accidental fast:: usage)
10// - Explicit .scalar() accessor (code-review signal for CT correctness)
11// - Destructor securely erases key material (volatile memset)
12// - Factory methods with strict validation (rejects 0 and >= n)
13//
14// Use PrivateKey instead of raw Scalar when handling long-lived secret keys.
15// Pass to ct::ecdsa_sign(), ct::schnorr_sign() etc. for safe signing.
16//
17// Example:
18// secp256k1::PrivateKey pk;
19// if (!secp256k1::PrivateKey::from_bytes(raw_key, pk)) { /* invalid */ }
20// auto sig = secp256k1::ct::ecdsa_sign(msg_hash, pk);
21// auto kp = secp256k1::ct::schnorr_keypair_create(pk);
22// ============================================================================
23
24#include <array>
25#include <cstdint>
26#include <cstring>
27#include "secp256k1/scalar.hpp"
29
30namespace secp256k1 {
31
33public:
34 // -- Construction (explicit only) -----------------------------------------
35
36 // Default: zero (invalid key, must be initialized via from_bytes).
37 PrivateKey() noexcept = default;
38
39 // Parse from 32-byte big-endian. Rejects values >= n or == 0.
40 // Returns false on invalid input (out is left zeroed).
41 [[nodiscard]] static bool from_bytes(const std::uint8_t* bytes32,
42 PrivateKey& out) noexcept {
43 return fast::Scalar::parse_bytes_strict_nonzero(bytes32, out.scalar_);
44 }
45 [[nodiscard]] static bool from_bytes(const std::array<std::uint8_t, 32>& bytes,
46 PrivateKey& out) noexcept {
47 return fast::Scalar::parse_bytes_strict_nonzero(bytes, out.scalar_);
48 }
49
50 // Wrap an already-validated scalar. Caller must ensure 0 < scalar < n.
51 // Named "wrap" to emphasize this bypasses validation.
52 [[nodiscard]] static PrivateKey wrap(const fast::Scalar& s) noexcept {
53 PrivateKey pk;
54 pk.scalar_ = s;
55 return pk;
56 }
57
58 // -- Access (explicit only) -----------------------------------------------
59
60 // Returns the underlying scalar for use in signing operations.
61 // WARNING: any call site using this MUST use ct:: operations for
62 // secret-dependent computation. Variable-time fast:: paths leak timing.
63 [[nodiscard]] const fast::Scalar& scalar() const noexcept { return scalar_; }
64
65 // Serialize to 32-byte big-endian.
66 [[nodiscard]] std::array<std::uint8_t, 32> to_bytes() const {
67 return scalar_.to_bytes();
68 }
69
70 // Check if the key is valid (nonzero).
71 [[nodiscard]] bool is_valid() const noexcept { return !scalar_.is_zero(); }
72
73 // -- No implicit conversion -----------------------------------------------
74 // Intentionally no operator Scalar() or operator const Scalar&().
75 // This forces callers to write .scalar() explicitly -- a code-review signal.
76
77 // -- Lifecycle ------------------------------------------------------------
78
79 ~PrivateKey() { secure_erase(); }
80
81 // Copy: allowed but zeroes are copied (no hidden state).
82 PrivateKey(const PrivateKey& other) noexcept : scalar_(other.scalar_) {}
83 PrivateKey& operator=(const PrivateKey& other) noexcept {
84 if (this != &other) {
85 secure_erase();
86 scalar_ = other.scalar_;
87 }
88 return *this;
89 }
90
91 // Move: source is zeroed after transfer.
92 PrivateKey(PrivateKey&& other) noexcept : scalar_(other.scalar_) {
93 other.secure_erase();
94 }
95 PrivateKey& operator=(PrivateKey&& other) noexcept {
96 if (this != &other) {
97 secure_erase();
98 scalar_ = other.scalar_;
99 other.secure_erase();
100 }
101 return *this;
102 }
103
104private:
105 void secure_erase() noexcept {
106 secp256k1::detail::secure_erase(&scalar_, sizeof(scalar_));
107 }
108
109 fast::Scalar scalar_{};
110};
111
112// Comparison (for testing; compares underlying scalars)
113inline bool operator==(const PrivateKey& a, const PrivateKey& b) noexcept {
114 return a.scalar() == b.scalar();
115}
116
117} // namespace secp256k1
118
119#endif // SECP256K1_PRIVATE_KEY_HPP
PrivateKey(const PrivateKey &other) noexcept
std::array< std::uint8_t, 32 > to_bytes() const
PrivateKey() noexcept=default
PrivateKey & operator=(PrivateKey &&other) noexcept
static bool from_bytes(const std::uint8_t *bytes32, PrivateKey &out) noexcept
bool is_valid() const noexcept
static bool from_bytes(const std::array< std::uint8_t, 32 > &bytes, PrivateKey &out) noexcept
const fast::Scalar & scalar() const noexcept
PrivateKey & operator=(const PrivateKey &other) noexcept
static PrivateKey wrap(const fast::Scalar &s) noexcept
PrivateKey(PrivateKey &&other) noexcept
static bool parse_bytes_strict_nonzero(const std::uint8_t *bytes32, Scalar &out) noexcept
std::array< std::uint8_t, 32 > to_bytes() const
bool is_zero() const noexcept
void secure_erase(void *ptr, std::size_t len) noexcept
bool operator==(const PrivateKey &a, const PrivateKey &b) noexcept