UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
arith64.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4
5namespace secp256k1::detail {
6
7#if defined(_MSC_VER) && !defined(__clang__)
8
9inline std::uint64_t add64(std::uint64_t a, std::uint64_t b, unsigned char& carry) {
10 unsigned __int64 out;
11 carry = _addcarry_u64(carry, a, b, &out);
12 return out;
13}
14
15inline std::uint64_t sub64(std::uint64_t a, std::uint64_t b, unsigned char& borrow) {
16 unsigned __int64 out;
17 borrow = _subborrow_u64(borrow, a, b, &out);
18 return out;
19}
20
21#else
22
23#ifdef SECP256K1_NO_INT128
24
25inline std::uint64_t add64(std::uint64_t a, std::uint64_t b, unsigned char& carry) {
26 std::uint64_t result = a + b;
27 unsigned char new_carry = (result < a) ? 1 : 0;
28 if (carry) {
29 std::uint64_t temp = result + 1;
30 new_carry |= (temp < result) ? 1 : 0;
31 result = temp;
32 }
33 carry = new_carry;
34 return result;
35}
36
37inline std::uint64_t sub64(std::uint64_t a, std::uint64_t b, unsigned char& borrow) {
38 std::uint64_t temp = a - borrow;
39 unsigned char const borrow1 = (a < borrow);
40 std::uint64_t result = temp - b;
41 unsigned char const borrow2 = (temp < b);
42 borrow = borrow1 | borrow2;
43 return result;
44}
45
46#else
47
48#if defined(__GNUC__)
49#pragma GCC diagnostic push
50#pragma GCC diagnostic ignored "-Wpedantic"
51#endif
52
53inline std::uint64_t add64(std::uint64_t a, std::uint64_t b, unsigned char& carry) {
54 unsigned __int128 const sum = static_cast<unsigned __int128>(a) + b + carry;
55 carry = static_cast<unsigned char>(sum >> 64);
56 return static_cast<std::uint64_t>(sum);
57}
58
59#if defined(__GNUC__)
60#pragma GCC diagnostic pop
61#endif
62
63inline std::uint64_t sub64(std::uint64_t a, std::uint64_t b, unsigned char& borrow) {
64 std::uint64_t const temp = a - borrow;
65 unsigned char const borrow1 = (a < borrow);
66 std::uint64_t const result = temp - b;
67 unsigned char const borrow2 = (temp < b);
68 borrow = borrow1 | borrow2;
69 return result;
70}
71
72#endif // SECP256K1_NO_INT128
73
74#endif // _MSC_VER
75
76// ---------------------------------------------------------------------------
77// mulhi64 -- upper 64 bits of unsigned 64x64 product
78// Use this instead of raw (unsigned __int128)(a*b)>>64 so that all callers
79// automatically pick the right path on MSVC vs. GCC/Clang.
80// ---------------------------------------------------------------------------
81#if defined(_MSC_VER) && !defined(__clang__)
82#include <intrin.h>
83inline std::uint64_t mulhi64(std::uint64_t a, std::uint64_t b) noexcept {
84 std::uint64_t hi;
85 _umul128(a, b, &hi);
86 return hi;
87}
88#elif defined(__SIZEOF_INT128__)
89#if defined(__GNUC__)
90#pragma GCC diagnostic push
91#pragma GCC diagnostic ignored "-Wpedantic"
92#endif
93inline std::uint64_t mulhi64(std::uint64_t a, std::uint64_t b) noexcept {
94 return static_cast<std::uint64_t>(
95 (static_cast<unsigned __int128>(a) * b) >> 64);
96}
97#if defined(__GNUC__)
98#pragma GCC diagnostic pop
99#endif
100#else
101// Fallback: schoolbook 32x32 multiply
102inline std::uint64_t mulhi64(std::uint64_t a, std::uint64_t b) noexcept {
103 std::uint32_t const ah = static_cast<std::uint32_t>(a >> 32);
104 std::uint32_t const al = static_cast<std::uint32_t>(a);
105 std::uint32_t const bh = static_cast<std::uint32_t>(b >> 32);
106 std::uint32_t const bl = static_cast<std::uint32_t>(b);
107 std::uint64_t const mid = static_cast<std::uint64_t>(al) * bh +
108 (static_cast<std::uint64_t>(ah) * bl) +
109 (static_cast<std::uint64_t>(al) * bl >> 32);
110 return static_cast<std::uint64_t>(ah) * bh + (mid >> 32);
111}
112#endif
113
114} // namespace secp256k1::detail
std::uint64_t add64(std::uint64_t a, std::uint64_t b, unsigned char &carry)
Definition arith64.hpp:53
std::uint64_t sub64(std::uint64_t a, std::uint64_t b, unsigned char &borrow)
Definition arith64.hpp:63
std::uint64_t mulhi64(std::uint64_t a, std::uint64_t b) noexcept
Definition arith64.hpp:102