UltrafastSecp256k1 3.68.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
field.hpp
Go to the documentation of this file.
1#ifndef B9C07A97_9853_412C_BCB7_F2FB19B8C1A7
2#define B9C07A97_9853_412C_BCB7_F2FB19B8C1A7
3
4#include <array>
5#include <cstdint>
6#include <cstring>
7#include <string>
8#include <vector>
9#include "config.hpp"
10#include "secp256k1/types.hpp"
11
12namespace secp256k1::fast {
13
14// Forward declaration
15class FieldElement;
16
17// ============================================================================
18// HYBRID 32/64-bit support: Zero-cost view for optimized operations
19// ============================================================================
20// MidFieldElement provides 32-bit limb view of FieldElement for operations
21// where 32-bit multiplication is faster (benchmarked 1.10x faster than 64-bit)
22// Memory layout is IDENTICAL - just different interpretation!
24 std::uint32_t limbs[8]; // Same 256 bits, different view
25
26 // Safe conversion back to 64-bit representation (memcpy, compiler-optimized to noop)
27 inline FieldElement ToFieldElement() const noexcept;
28};
29
31public:
32 using limbs_type = std::array<std::uint64_t, 4>;
33
36 static FieldElement one();
37 static FieldElement from_uint64(std::uint64_t value);
39 static FieldElement from_bytes(const std::array<std::uint8_t, 32>& bytes);
40
41 // BIP-340 strict parsing: rejects values >= field prime p (no reduction).
42 // Returns false if bytes represent a value >= p.
43 // Use for pubkey/signature r-value parsing where canonical encoding is required.
44 static bool parse_bytes_strict(const std::uint8_t* bytes32, FieldElement& out) noexcept;
45 static bool parse_bytes_strict(const std::array<std::uint8_t, 32>& bytes, FieldElement& out) noexcept;
46
47 // Convert from Montgomery domain (a*R) to Standard domain (a)
49
50 // Developer-friendly: Create from hex string (64 hex chars)
51 // Example: FieldElement::from_hex("09af57f4f5c1d64c6bea6d4193c5d9130421f4f078868e5ec00a56e68001136c")
52 static FieldElement from_hex(const std::string& hex);
53
54 std::array<std::uint8_t, 32> to_bytes() const;
55 // Write 32 big-endian bytes into provided buffer (avoids temporary array)
56 void to_bytes_into(std::uint8_t* out) const noexcept;
57 std::string to_hex() const;
58 const limbs_type& limbs() const noexcept { return limbs_; }
59
60 // Non-const limb access for assembly wrappers that write into result directly.
61 // Avoids const_cast UB. Caller must ensure the written values are canonical.
62 limbs_type& limbs_mut() noexcept { return limbs_; }
63
64 // Raw limb setter (no normalization) -- for use when caller guarantees canonical form.
65 // Used by FieldElement52::to_fe() which already normalizes via fe52_normalize_inline.
66 static FieldElement from_limbs_raw(const limbs_type& limbs) noexcept {
67 FieldElement fe;
68 fe.limbs_ = limbs;
69 return fe;
70 }
71
77
78 // Square root: a^((p+1)/4) mod p. Valid since p == 3 (mod 4).
79 // Uses an optimized addition chain (~255 sqr + 13 mul).
80 // Returns a root r such that r^2 == a (mod p). Caller must verify r^2==a.
82
86
87 // Modular negation: returns p - this (mod p).
88 // `magnitude` parameter exists for API compatibility with FieldElement52/26
89 // (lazy-reduction magnitude tracking); ignored here since FE64 is always normalized.
90 FieldElement negate(unsigned magnitude = 1) const;
91 void negate_assign(unsigned magnitude = 1);
92
93 // No-op for API compatibility with FieldElement52/26 which track lazy-reduction
94 // magnitude and may need normalization. FE64 is always fully normalized.
95 void normalize_weak() noexcept {}
96
97 // In-place mutable versions (modify this object directly)
98 // ~10-15% faster than immutable versions due to no memory allocation
99 void square_inplace(); // this = this^2 (modifies this)
100 void inverse_inplace(); // this = this^-^1 (modifies this)
101
102 bool operator==(const FieldElement& rhs) const noexcept;
103
104 // Safe conversion to shared data type (memcpy, compiler-optimized to noop).
105 // Returns by value -- no strict-aliasing UB.
108 std::memcpy(&d, &limbs_, sizeof(d));
109 return d;
110 }
111 static FieldElement from_data(const ::secp256k1::FieldElementData& d) {
112 return from_limbs({d.limbs[0], d.limbs[1], d.limbs[2], d.limbs[3]});
113 }
114
115private:
116 explicit FieldElement(const limbs_type& limbs, bool normalized);
117
118 limbs_type limbs_{};
119};
120
121// Safe conversions for FieldElement <-> MidFieldElement (memcpy, compiler-optimized)
122inline MidFieldElement toMid(const FieldElement& fe) noexcept {
123 MidFieldElement mid;
124 std::memcpy(&mid, &fe, sizeof(mid));
125 return mid;
126}
127
128// Deferred inline definition (needs FieldElement to be complete)
131 std::memcpy(&lm, limbs, sizeof(lm));
133}
134
135// Compile-time verification
136static_assert(sizeof(FieldElement) == sizeof(MidFieldElement),
137 "FieldElement and MidFieldElement must be same size");
138static_assert(sizeof(FieldElement) == 32, "Must be 256 bits");
139
140// Cross-backend layout compatibility (shared types contract)
141static_assert(sizeof(FieldElement) == sizeof(::secp256k1::FieldElementData),
142 "CPU FieldElement must match shared data layout size");
143static_assert(sizeof(MidFieldElement) == sizeof(::secp256k1::MidFieldElementData),
144 "CPU MidFieldElement must match shared data layout size");
145static_assert(sizeof(FieldElement) == 32, "Must be 256 bits");
146
147// ============================================================================
148// Montgomery Domain Constants
149// ============================================================================
150// Montgomery domain: R = 2^256 mod p
151// For secp256k1, p = 2^256 - 0x1000003D1, so R = 0x1000003D1
152//
153// Usage:
154// - to_mont(a) = (a * R^2) mod p // Convert a -> a*R
155// - from_mont(aR) = (aR * R^-^1) mod p // Convert a*R -> a
156// - mont_mul(aR, bR) = (aR * bR * R^-^1) mod p = (ab)R // Stays in Montgomery
157//
158// Benefits:
159// - Modular reduction uses cheap multiplication instead of division
160// - 10-15% faster in batch operations
161// - Required for GPU H-based inversion pipeline
162
163namespace montgomery {
164 // R = 2^256 mod p = 0x1000003D1
165 inline const FieldElement& R() {
166 static const FieldElement r = FieldElement::from_uint64(0x1000003D1ULL);
167 return r;
168 }
169
170 // R^2 mod p = (2^256)^2 mod p = 0x000007A2000E90A1
171 inline const FieldElement& R2() {
172 static const FieldElement r2 = FieldElement::from_limbs(
173 {0x000007A2000E90A1ULL, 0x0000000000000001ULL, 0ULL, 0ULL});
174 return r2;
175 }
176
177 // R^3 mod p = (2^256)^3 mod p
178 inline const FieldElement& R3() {
179 static const FieldElement r3 = FieldElement::from_limbs(
180 {0x002BB1E33795F671ULL, 0x0000000100000B73ULL, 0ULL, 0ULL});
181 return r3;
182 }
183
184 // R^-^1 mod p = (2^256)^-^1 mod p
185 inline const FieldElement& R_inv() {
186 static const FieldElement r_inv = FieldElement::from_limbs(
187 {0xD838091D0868192AULL, 0xBCB223FEDC24A059ULL,
188 0x9C46C2C295F2B761ULL, 0xC9BD190515538399ULL});
189 return r_inv;
190 }
191
192 // K = 2^32 + 977 = 0x1000003D1 (secp256k1 reduction constant)
193 constexpr std::uint64_t K_MOD = 0x1000003D1ULL;
194}
195
196// ============================================================================
197// Field Element Arithmetic Functions
198// ============================================================================
199
204
205// Direct access to internal pow_p_minus_2 implementations for benchmarking
219
220// New optimized methods - Round 2
227
228// Round 3 - GPU-optimized and ECC-specific
240
241// Wrapper functions
252
253// New optimized wrappers
260
261// Round 3 wrappers
273
274// Montgomery batch inversion - invert N field elements simultaneously
275// Uses Montgomery's trick: (a*b*c)^-1 -> compute individual a^-1, b^-1, c^-1
276// Cost: 1 inverse + 3*(N-1) multiplications instead of N inverses
277// For N=8: ~8 us instead of 28 us (3.5x speedup!)
278void fe_batch_inverse(FieldElement* elements, size_t count);
279
280// Zero-allocation version: uses provided scratch buffer
281// scratch buffer must be at least size 'count'
282void fe_batch_inverse(FieldElement* elements, size_t count, std::vector<FieldElement>& scratch);
283
284} // namespace secp256k1::fast
285
286// Direct 5x52 SafeGCD inverse — bypasses 4x64 intermediate.
287// Input: 5 limbs (52-bit each, normalized). Output: 5 limbs (52-bit, normalized).
288// Declared outside namespace for C-style linkage from FE52 code.
289#if defined(__SIZEOF_INT128__)
290namespace secp256k1::fast {
291void fe52_inverse_safegcd_var(const std::uint64_t* in5, std::uint64_t* out5);
292}
293#endif
294
295
296#endif /* B9C07A97_9853_412C_BCB7_F2FB19B8C1A7 */
const limbs_type & limbs() const noexcept
Definition field.hpp:58
FieldElement & operator+=(const FieldElement &rhs)
FieldElement square() const
FieldElement operator+(const FieldElement &rhs) const
static bool parse_bytes_strict(const std::uint8_t *bytes32, FieldElement &out) noexcept
FieldElement & operator*=(const FieldElement &rhs)
limbs_type & limbs_mut() noexcept
Definition field.hpp:62
std::array< std::uint64_t, 4 > limbs_type
Definition field.hpp:32
std::array< std::uint8_t, 32 > to_bytes() const
bool operator==(const FieldElement &rhs) const noexcept
static FieldElement from_data(const ::secp256k1::FieldElementData &d)
Definition field.hpp:111
void normalize_weak() noexcept
Definition field.hpp:95
FieldElement & operator-=(const FieldElement &rhs)
static FieldElement from_hex(const std::string &hex)
static FieldElement zero()
static FieldElement from_limbs_raw(const limbs_type &limbs) noexcept
Definition field.hpp:66
::secp256k1::FieldElementData data() const noexcept
Definition field.hpp:106
static FieldElement from_mont(const FieldElement &a)
static FieldElement from_limbs(const limbs_type &limbs)
FieldElement operator*(const FieldElement &rhs) const
FieldElement operator-(const FieldElement &rhs) const
std::string to_hex() const
FieldElement inverse() const
static FieldElement one()
void negate_assign(unsigned magnitude=1)
static bool parse_bytes_strict(const std::array< std::uint8_t, 32 > &bytes, FieldElement &out) noexcept
static FieldElement from_uint64(std::uint64_t value)
void to_bytes_into(std::uint8_t *out) const noexcept
FieldElement negate(unsigned magnitude=1) const
static FieldElement from_bytes(const std::array< std::uint8_t, 32 > &bytes)
FieldElement sqrt() const
secp256k1::fast::FieldElement FieldElement
Definition field.hpp:33
FieldElement fe_inverse_secp256k1_special(const FieldElement &value)
FieldElement pow_p_minus_2_rtl_binary(FieldElement base)
FieldElement pow_p_minus_2_yao(FieldElement base)
FieldElement pow_p_minus_2_binary(FieldElement base)
FieldElement fe_inverse_strauss(const FieldElement &value)
FieldElement pow_p_minus_2_binary_euclidean(FieldElement base)
FieldElement pow_p_minus_2_addchain(FieldElement base)
FieldElement fe_inverse_kary16(const FieldElement &value)
FieldElement pow_p_minus_2_montgomery_redc(FieldElement base)
FieldElement pow_p_minus_2_double_base(const FieldElement &base)
FieldElement pow_p_minus_2_pippenger(FieldElement base)
FieldElement fe_inverse_bos_coster(const FieldElement &value)
FieldElement fe_inverse_window_naf_v2(const FieldElement &value)
FieldElement fe_inverse_ltr_precomp(const FieldElement &value)
FieldElement pow_p_minus_2_lehmer(FieldElement base)
FieldElement fe_inverse_binary_euclidean(const FieldElement &value)
FieldElement fe_inverse_fermat_gpu(const FieldElement &value)
FieldElement pow_p_minus_2_stein(FieldElement base)
FieldElement pow_p_minus_2_window4(FieldElement base)
MidFieldElement toMid(const FieldElement &fe) noexcept
Definition field.hpp:122
FieldElement fe_inverse_safegcd(const FieldElement &value)
FieldElement pow_p_minus_2_ltr_precomp(FieldElement base)
FieldElement fe_inverse_branchless(const FieldElement &value)
FieldElement fe_inverse_parallel_window(const FieldElement &value)
FieldElement pow_p_minus_2_kary16(FieldElement base)
FieldElement pow_p_minus_2_window_naf_v2(FieldElement base)
void fe_batch_inverse(FieldElement *elements, size_t count)
FieldElement pow_p_minus_2_compact_table(FieldElement base)
FieldElement pow_p_minus_2_sliding_dynamic(FieldElement base)
FieldElement fe_inverse_eea(const FieldElement &value)
FieldElement fe_inverse_double_base(const FieldElement &value)
FieldElement fe_inverse_karatsuba(const FieldElement &value)
FieldElement fe_inverse_compact_table(const FieldElement &value)
FieldElement pow_p_minus_2_booth(FieldElement base)
FieldElement pow_p_minus_2_binary_opt(FieldElement base)
FieldElement fe_inverse_warp_optimized(const FieldElement &value)
FieldElement pow_p_minus_2_warp_optimized(FieldElement base)
FieldElement fe_inverse_addchain(const FieldElement &value)
FieldElement pow_p_minus_2_hybrid_eea(FieldElement base)
FieldElement fe_inverse_montgomery_redc(const FieldElement &value)
FieldElement fe_inverse_fixed_window5(const FieldElement &value)
FieldElement pow_p_minus_2_eea(FieldElement base)
FieldElement fe_inverse_lehmer(const FieldElement &value)
FieldElement fe_inverse_sliding_dynamic(const FieldElement &value)
FieldElement pow_p_minus_2_strauss(FieldElement base)
FieldElement fe_inverse_binary(const FieldElement &value)
FieldElement pow_p_minus_2_secp256k1_special(FieldElement base)
FieldElement pow_p_minus_2_fermat_gpu(FieldElement base)
FieldElement pow_p_minus_2_bos_coster(FieldElement base)
FieldElement fe_inverse_addchain_unrolled(const FieldElement &value)
FieldElement fe_inverse_stein(const FieldElement &value)
FieldElement fe_inverse_binary_opt(const FieldElement &value)
FieldElement pow_p_minus_2_parallel_window(FieldElement base)
FieldElement fe_inverse_window4(const FieldElement &value)
FieldElement fe_inverse_booth(const FieldElement &value)
FieldElement fe_inverse_pippenger(const FieldElement &value)
FieldElement pow_p_minus_2_addchain_unrolled(FieldElement base)
FieldElement pow_p_minus_2_fixed_window5(FieldElement base)
FieldElement pow_p_minus_2_karatsuba(FieldElement base)
FieldElement fe_inverse_rtl_binary(const FieldElement &value)
FieldElement pow_p_minus_2_branchless(FieldElement base)
FieldElement fe_inverse_hybrid_eea(const FieldElement &value)
FieldElement fe_inverse_yao(const FieldElement &value)
FieldElement ToFieldElement() const noexcept
Definition field.hpp:129