UltrafastSecp256k1 3.50.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 // In-place mutable versions (modify this object directly)
94 // ~10-15% faster than immutable versions due to no memory allocation
95 void square_inplace(); // this = this^2 (modifies this)
96 void inverse_inplace(); // this = this^-^1 (modifies this)
97
98 bool operator==(const FieldElement& rhs) const noexcept;
99
100 // Safe conversion to shared data type (memcpy, compiler-optimized to noop).
101 // Returns by value -- no strict-aliasing UB.
104 std::memcpy(&d, &limbs_, sizeof(d));
105 return d;
106 }
107 static FieldElement from_data(const ::secp256k1::FieldElementData& d) {
108 return from_limbs({d.limbs[0], d.limbs[1], d.limbs[2], d.limbs[3]});
109 }
110
111private:
112 explicit FieldElement(const limbs_type& limbs, bool normalized);
113
114 limbs_type limbs_{};
115};
116
117// Safe conversions for FieldElement <-> MidFieldElement (memcpy, compiler-optimized)
118inline MidFieldElement toMid(const FieldElement& fe) noexcept {
119 MidFieldElement mid;
120 std::memcpy(&mid, &fe, sizeof(mid));
121 return mid;
122}
123
124// Deferred inline definition (needs FieldElement to be complete)
127 std::memcpy(&lm, limbs, sizeof(lm));
129}
130
131// Compile-time verification
132static_assert(sizeof(FieldElement) == sizeof(MidFieldElement),
133 "FieldElement and MidFieldElement must be same size");
134static_assert(sizeof(FieldElement) == 32, "Must be 256 bits");
135
136// Cross-backend layout compatibility (shared types contract)
137static_assert(sizeof(FieldElement) == sizeof(::secp256k1::FieldElementData),
138 "CPU FieldElement must match shared data layout size");
139static_assert(sizeof(MidFieldElement) == sizeof(::secp256k1::MidFieldElementData),
140 "CPU MidFieldElement must match shared data layout size");
141static_assert(sizeof(FieldElement) == 32, "Must be 256 bits");
142
143// ============================================================================
144// Montgomery Domain Constants
145// ============================================================================
146// Montgomery domain: R = 2^256 mod p
147// For secp256k1, p = 2^256 - 0x1000003D1, so R = 0x1000003D1
148//
149// Usage:
150// - to_mont(a) = (a * R^2) mod p // Convert a -> a*R
151// - from_mont(aR) = (aR * R^-^1) mod p // Convert a*R -> a
152// - mont_mul(aR, bR) = (aR * bR * R^-^1) mod p = (ab)R // Stays in Montgomery
153//
154// Benefits:
155// - Modular reduction uses cheap multiplication instead of division
156// - 10-15% faster in batch operations
157// - Required for GPU H-based inversion pipeline
158
159namespace montgomery {
160 // R = 2^256 mod p = 0x1000003D1
161 inline const FieldElement& R() {
162 static const FieldElement r = FieldElement::from_uint64(0x1000003D1ULL);
163 return r;
164 }
165
166 // R^2 mod p = (2^256)^2 mod p = 0x000007A2000E90A1
167 inline const FieldElement& R2() {
168 static const FieldElement r2 = FieldElement::from_limbs(
169 {0x000007A2000E90A1ULL, 0x0000000000000001ULL, 0ULL, 0ULL});
170 return r2;
171 }
172
173 // R^3 mod p = (2^256)^3 mod p
174 inline const FieldElement& R3() {
175 static const FieldElement r3 = FieldElement::from_limbs(
176 {0x002BB1E33795F671ULL, 0x0000000100000B73ULL, 0ULL, 0ULL});
177 return r3;
178 }
179
180 // R^-^1 mod p = (2^256)^-^1 mod p
181 inline const FieldElement& R_inv() {
182 static const FieldElement r_inv = FieldElement::from_limbs(
183 {0xD838091D0868192AULL, 0xBCB223FEDC24A059ULL,
184 0x9C46C2C295F2B761ULL, 0xC9BD190515538399ULL});
185 return r_inv;
186 }
187
188 // K = 2^32 + 977 = 0x1000003D1 (secp256k1 reduction constant)
189 constexpr std::uint64_t K_MOD = 0x1000003D1ULL;
190}
191
192// ============================================================================
193// Field Element Arithmetic Functions
194// ============================================================================
195
200
201// Direct access to internal pow_p_minus_2 implementations for benchmarking
215
216// New optimized methods - Round 2
223
224// Round 3 - GPU-optimized and ECC-specific
236
237// Wrapper functions
248
249// New optimized wrappers
256
257// Round 3 wrappers
269
270// Montgomery batch inversion - invert N field elements simultaneously
271// Uses Montgomery's trick: (a*b*c)^-1 -> compute individual a^-1, b^-1, c^-1
272// Cost: 1 inverse + 3*(N-1) multiplications instead of N inverses
273// For N=8: ~8 us instead of 28 us (3.5x speedup!)
274void fe_batch_inverse(FieldElement* elements, size_t count);
275
276// Zero-allocation version: uses provided scratch buffer
277// scratch buffer must be at least size 'count'
278void fe_batch_inverse(FieldElement* elements, size_t count, std::vector<FieldElement>& scratch);
279
280} // namespace secp256k1::fast
281
282// Direct 5x52 SafeGCD inverse — bypasses 4x64 intermediate.
283// Input: 5 limbs (52-bit each, normalized). Output: 5 limbs (52-bit, normalized).
284// Declared outside namespace for C-style linkage from FE52 code.
285#if defined(__SIZEOF_INT128__)
286namespace secp256k1::fast {
287void fe52_inverse_safegcd_var(const std::uint64_t* in5, std::uint64_t* out5);
288}
289#endif
290
291
292#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:107
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:102
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:118
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:125