UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
hash_accel.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_HASH_ACCEL_HPP
2#define SECP256K1_HASH_ACCEL_HPP
3#pragma once
4
5// ============================================================================
6// Accelerated Hashing -- SHA-256 / RIPEMD-160 / Hash160
7// ============================================================================
8//
9// ## Three tiers of acceleration (runtime-detected):
10//
11// Tier 0: SCALAR -- Portable C++ (baseline, always available)
12// Tier 1: ARM SHA2 -- ARMv8 SHA-256 instructions (single-message HW accel)
13// Tier 2: SHA-NI -- Intel SHA Extensions (single-message HW accel, ~3-5x)
14// Tier 3: AVX2 -- 4-way multi-buffer SHA-256 (interleaved, ~8-12x)
15// + optimized RIPEMD-160 with BMI/BMI2
16// Tier 4: AVX-512 -- 8-way multi-buffer SHA-256 (if available, ~16x)
17//
18// ## Hot-path API for search pipeline:
19//
20// Compressed pubkey (33 bytes) -> SHA-256 -> RIPEMD-160 = Hash160 (20 bytes)
21//
22// - hash160_single(): single pubkey -> 20 bytes
23// - hash160_batch(): N pubkeys -> Nx20 bytes (multi-buffer SIMD)
24// - sha256_33(): SHA-256 of exactly 33 bytes (pubkey-optimized)
25// - ripemd160_32(): RIPEMD-160 of exactly 32 bytes (SHA output)
26//
27// ## Pubkey-specific optimization:
28//
29// SHA-256(33 bytes) always produces exactly 1 block (33 + 1 + 22 + 8 = 64).
30// The padding is constant and can be precomputed. This eliminates all
31// branching, length encoding, and buffer management from the hot path.
32//
33// ============================================================================
34
35#include <array>
36#include <cstdint>
37#include <cstddef>
38
39// Architecture detection (must match hash_accel.cpp)
40#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
41 #ifndef SECP256K1_X86_TARGET
42 #define SECP256K1_X86_TARGET 1
43 #endif
44#endif
45
46namespace secp256k1::hash {
47
48// -- Feature Detection --------------------------------------------------------
49
50enum class HashTier : int {
51 SCALAR = 0,
52 ARM_SHA2 = 1, // ARMv8 SHA-256 instructions
53 SHA_NI = 2, // Intel SHA Extensions
54 AVX2 = 3, // 4-way multi-buffer
55 AVX512 = 4, // 8-way multi-buffer
56};
57
60
62const char* hash_tier_name(HashTier tier) noexcept;
63
65bool sha_ni_available() noexcept;
66bool avx2_available() noexcept;
67bool avx512_available() noexcept;
68
69// -- Single-message SHA-256 ---------------------------------------------------
70
72std::array<std::uint8_t, 32> sha256(const void* data, std::size_t len) noexcept;
73
76void sha256_33(const std::uint8_t* pubkey33, std::uint8_t* out32) noexcept;
77
79void sha256_32(const std::uint8_t* in32, std::uint8_t* out32) noexcept;
80
82std::array<std::uint8_t, 32> sha256d(const void* data, std::size_t len) noexcept;
83
84// -- Single-message RIPEMD-160 ------------------------------------------------
85
87std::array<std::uint8_t, 20> ripemd160(const void* data, std::size_t len) noexcept;
88
91void ripemd160_32(const std::uint8_t* in32, std::uint8_t* out20) noexcept;
92
93// -- Hash160 -- RIPEMD160(SHA256(data)) ----------------------------------------
94
96std::array<std::uint8_t, 20> hash160(const void* data, std::size_t len) noexcept;
97
100void hash160_33(const std::uint8_t* pubkey33, std::uint8_t* out20) noexcept;
101
102// -- Batch operations (multi-buffer SIMD) -------------------------------------
103//
104// Process multiple independent messages simultaneously using SIMD lanes.
105// AVX2: 4 messages per cycle, AVX-512: 8 messages per cycle.
106// Falls back to sequential scalar/SHA-NI when SIMD unavailable.
107//
108// All batch functions expect contiguous arrays:
109// - Input: pubkeys[count * 33] (packed, no gaps)
110// - Output: hashes[count * output_size] (packed, no gaps)
111//
112// Hot-path contract: No heap allocation if scratch is pre-sized.
113
117 const std::uint8_t* pubkeys, // count x 33 bytes (packed)
118 std::uint8_t* out32s, // count x 32 bytes output
119 std::size_t count) noexcept;
120
124 const std::uint8_t* in32s, // count x 32 bytes
125 std::uint8_t* out20s, // count x 20 bytes output
126 std::size_t count) noexcept;
127
132 const std::uint8_t* pubkeys, // count x 33 bytes (packed)
133 std::uint8_t* out20s, // count x 20 bytes output
134 std::size_t count) noexcept;
135
136// -- Implementation selectors (for benchmarking / testing) --------------------
137// These bypass auto-detection to force a specific tier.
138
139namespace scalar {
140 void sha256_compress(const std::uint8_t block[64], std::uint32_t state[8]) noexcept;
141 void sha256_33(const std::uint8_t* pubkey33, std::uint8_t* out32) noexcept;
142 void sha256_32(const std::uint8_t* in32, std::uint8_t* out32) noexcept;
143 void ripemd160_compress(const std::uint8_t block[64], std::uint32_t state[5]) noexcept;
144 void ripemd160_32(const std::uint8_t* in32, std::uint8_t* out20) noexcept;
145 void hash160_33(const std::uint8_t* pubkey33, std::uint8_t* out20) noexcept;
146}
147
148#ifdef SECP256K1_X86_TARGET
149namespace shani {
150 void sha256_compress(const std::uint8_t block[64], std::uint32_t state[8]) noexcept;
151 void sha256_33(const std::uint8_t* pubkey33, std::uint8_t* out32) noexcept;
152 void sha256_32(const std::uint8_t* in32, std::uint8_t* out32) noexcept;
153 void hash160_33(const std::uint8_t* pubkey33, std::uint8_t* out20) noexcept;
154}
155#endif
156
157} // namespace secp256k1::hash
158
159#endif // SECP256K1_HASH_ACCEL_HPP
void sha256_compress(const std::uint8_t block[64], std::uint32_t state[8]) noexcept
void ripemd160_compress(const std::uint8_t block[64], std::uint32_t state[5]) noexcept
void ripemd160_32(const std::uint8_t *in32, std::uint8_t *out20) noexcept
void hash160_33_batch(const std::uint8_t *pubkeys, std::uint8_t *out20s, std::size_t count) noexcept
void sha256_33(const std::uint8_t *pubkey33, std::uint8_t *out32) noexcept
std::array< std::uint8_t, 20 > ripemd160(const void *data, std::size_t len) noexcept
RIPEMD-160 of arbitrary data (auto-selects best implementation).
void hash160_33(const std::uint8_t *pubkey33, std::uint8_t *out20) noexcept
std::array< std::uint8_t, 32 > sha256(const void *data, std::size_t len) noexcept
SHA-256 of arbitrary data (auto-selects best implementation).
void sha256_32(const std::uint8_t *in32, std::uint8_t *out32) noexcept
SHA-256 of exactly 32 bytes (e.g. second hash in double-SHA256)
std::array< std::uint8_t, 32 > sha256d(const void *data, std::size_t len) noexcept
Double-SHA256: SHA256(SHA256(data)) for arbitrary data.
void sha256_33_batch(const std::uint8_t *pubkeys, std::uint8_t *out32s, std::size_t count) noexcept
bool sha_ni_available() noexcept
Check individual features.
HashTier detect_hash_tier() noexcept
Detect best available hashing tier at runtime.
bool avx2_available() noexcept
const char * hash_tier_name(HashTier tier) noexcept
Human-readable tier name.
void ripemd160_32_batch(const std::uint8_t *in32s, std::uint8_t *out20s, std::size_t count) noexcept
std::array< std::uint8_t, 20 > hash160(const void *data, std::size_t len) noexcept
Hash160 of arbitrary data.
bool avx512_available() noexcept