UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
sha256.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_SHA256_HPP
2#define SECP256K1_SHA256_HPP
3#pragma once
4
5// ============================================================================
6// SHA-256 implementation for ECDSA / Schnorr
7// ============================================================================
8// Hardware-accelerated via SHA-NI when available (runtime dispatch).
9// Falls back to portable C++ on non-x86 or CPUs without SHA extensions.
10// ============================================================================
11
12#include <array>
13#include <cstdint>
14#include <cstddef>
15#include <cstring>
16
17namespace secp256k1 {
18
19// Forward declare: implemented in hash_accel.cpp, dispatches to SHA-NI or scalar
20namespace detail {
21#if defined(__GNUC__) || defined(__clang__)
22 __attribute__((hot))
23#endif
24 void sha256_compress_dispatch(const std::uint8_t block[64],
25 std::uint32_t state[8]) noexcept;
26}
27
28class SHA256 {
29public:
30 using digest_type = std::array<std::uint8_t, 32>;
31
32 SHA256() noexcept { reset(); }
33
34 void reset() noexcept {
35 state_[0] = 0x6a09e667u; state_[1] = 0xbb67ae85u;
36 state_[2] = 0x3c6ef372u; state_[3] = 0xa54ff53au;
37 state_[4] = 0x510e527fu; state_[5] = 0x9b05688cu;
38 state_[6] = 0x1f83d9abu; state_[7] = 0x5be0cd19u;
39 total_ = 0;
40 buf_len_ = 0;
41 }
42
43 void update(const void* data, std::size_t len) noexcept {
44 auto ptr = static_cast<const std::uint8_t*>(data);
45 total_ += len;
46
47 if (buf_len_ > 0) {
48 std::size_t const fill = 64 - buf_len_;
49 if (len < fill) {
50 std::memcpy(buf_ + buf_len_, ptr, len);
51 buf_len_ += len;
52 return;
53 }
54 std::memcpy(buf_ + buf_len_, ptr, fill);
56 ptr += fill;
57 len -= fill;
58 buf_len_ = 0;
59 }
60
61 while (len >= 64) {
63 ptr += 64;
64 len -= 64;
65 }
66
67 if (len > 0) {
68 std::memcpy(buf_, ptr, len);
69 buf_len_ = len;
70 }
71 }
72
73 digest_type finalize() noexcept {
74 std::uint64_t const bits = total_ * 8;
75
76 // -- Direct in-place padding (no per-byte update() calls) ---------
77 // buf_len_ is invariantly [0,63] after update() processes full blocks.
78 // Explicit bounds check satisfies static analysis (Sonar cpp:S3519).
79 if (buf_len_ >= 64) buf_len_ = 0;
80 std::size_t const pos = buf_len_; // capture index before increment
81 buf_len_ = pos + 1; // new length [1, 64]
82 buf_[pos] = 0x80; // write at [0, 63] -- always in bounds
83
84 if (buf_len_ > 56) {
85 // No room for 8-byte length -- pad, compress, start fresh block
86 // buf_len_ is [57, 64]; (64 - buf_len_) is [0, 7]
87 if (buf_len_ < 64) {
88 std::memset(buf_ + buf_len_, 0, 64 - buf_len_);
89 }
91 buf_len_ = 0;
92 }
93
94 // Zero-pad to byte 56
95 std::memset(buf_ + buf_len_, 0, 56 - buf_len_);
96
97 // Append bit-length big-endian at bytes 56..63
98 buf_[56] = static_cast<std::uint8_t>(bits >> 56);
99 buf_[57] = static_cast<std::uint8_t>(bits >> 48);
100 buf_[58] = static_cast<std::uint8_t>(bits >> 40);
101 buf_[59] = static_cast<std::uint8_t>(bits >> 32);
102 buf_[60] = static_cast<std::uint8_t>(bits >> 24);
103 buf_[61] = static_cast<std::uint8_t>(bits >> 16);
104 buf_[62] = static_cast<std::uint8_t>(bits >> 8);
105 buf_[63] = static_cast<std::uint8_t>(bits);
106
108
109 digest_type out{};
110 for (std::size_t i = 0; i < 8; ++i) {
111 out[i * 4 + 0] = static_cast<std::uint8_t>(state_[i] >> 24);
112 out[i * 4 + 1] = static_cast<std::uint8_t>(state_[i] >> 16);
113 out[i * 4 + 2] = static_cast<std::uint8_t>(state_[i] >> 8);
114 out[i * 4 + 3] = static_cast<std::uint8_t>(state_[i]);
115 }
116 return out;
117 }
118
119 // One-shot convenience
120 static digest_type hash(const void* data, std::size_t len) noexcept {
121 SHA256 ctx;
122 ctx.update(data, len);
123 return ctx.finalize();
124 }
125
126 // Double-SHA256: SHA256(SHA256(data))
127 static digest_type hash256(const void* data, std::size_t len) noexcept {
128 auto h1 = hash(data, len);
129 return hash(h1.data(), h1.size());
130 }
131
132private:
133 std::uint32_t state_[8]{};
134 std::uint8_t buf_[64]{};
135 std::size_t buf_len_ = 0;
136 std::uint64_t total_ = 0;
137};
138
139} // namespace secp256k1
140
141#endif // SECP256K1_SHA256_HPP
static digest_type hash(const void *data, std::size_t len) noexcept
Definition sha256.hpp:120
void reset() noexcept
Definition sha256.hpp:34
static digest_type hash256(const void *data, std::size_t len) noexcept
Definition sha256.hpp:127
SHA256() noexcept
Definition sha256.hpp:32
digest_type finalize() noexcept
Definition sha256.hpp:73
void update(const void *data, std::size_t len) noexcept
Definition sha256.hpp:43
std::array< std::uint8_t, 32 > digest_type
Definition sha256.hpp:30
void sha256_compress_dispatch(const std::uint8_t block[64], std::uint32_t state[8]) noexcept