/src/serenity/Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> |
3 | | * Copyright (c) 2022, the SerenityOS developers. |
4 | | * Copyright (c) 2022, David Tuin <davidot@serenityos.org> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | */ |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <AK/BigIntBase.h> |
12 | | #include <AK/ByteBuffer.h> |
13 | | #include <AK/ByteString.h> |
14 | | #include <AK/Concepts.h> |
15 | | #include <AK/Span.h> |
16 | | #include <AK/String.h> |
17 | | #include <AK/Types.h> |
18 | | #include <AK/Vector.h> |
19 | | |
20 | | namespace Crypto { |
21 | | |
22 | | struct UnsignedDivisionResult; |
23 | | constexpr size_t STARTING_WORD_SIZE = 32; |
24 | | |
25 | | class UnsignedBigInteger { |
26 | | public: |
27 | | using Word = u32; |
28 | | using StorageSpan = AK::Detail::StorageSpan<Word, false>; |
29 | | using ConstStorageSpan = AK::Detail::StorageSpan<Word const, false>; |
30 | | static constexpr size_t BITS_IN_WORD = 32; |
31 | | |
32 | | // This constructor accepts any unsigned with size up to Word. |
33 | | template<Integral T> |
34 | | requires(sizeof(T) <= sizeof(Word)) |
35 | | UnsignedBigInteger(T value) |
36 | 25.9k | { |
37 | 25.9k | m_words.append(static_cast<Word>(value)); |
38 | 25.9k | } _ZN6Crypto18UnsignedBigIntegerC2ITkN2AK8Concepts8IntegralEjQlestT_Lm4EEES4_ Line | Count | Source | 36 | 3.54k | { | 37 | 3.54k | m_words.append(static_cast<Word>(value)); | 38 | 3.54k | } |
_ZN6Crypto18UnsignedBigIntegerC2ITkN2AK8Concepts8IntegralEiQlestT_Lm4EEES4_ Line | Count | Source | 36 | 19.4k | { | 37 | 19.4k | m_words.append(static_cast<Word>(value)); | 38 | 19.4k | } |
_ZN6Crypto18UnsignedBigIntegerC2ITkN2AK8Concepts8IntegralEtQlestT_Lm4EEES4_ Line | Count | Source | 36 | 160 | { | 37 | 160 | m_words.append(static_cast<Word>(value)); | 38 | 160 | } |
_ZN6Crypto18UnsignedBigIntegerC2ITkN2AK8Concepts8IntegralEbQlestT_Lm4EEES4_ Line | Count | Source | 36 | 2.73k | { | 37 | 2.73k | m_words.append(static_cast<Word>(value)); | 38 | 2.73k | } |
|
39 | | |
40 | | explicit UnsignedBigInteger(Vector<Word, STARTING_WORD_SIZE>&& words) |
41 | | : m_words(move(words)) |
42 | 0 | { |
43 | 0 | } |
44 | | |
45 | | explicit UnsignedBigInteger(u8 const* ptr, size_t length); |
46 | | |
47 | | explicit UnsignedBigInteger(double value); |
48 | | |
49 | | explicit UnsignedBigInteger(u64 value) |
50 | 4 | { |
51 | 4 | static_assert(sizeof(u64) == sizeof(Word) * 2); |
52 | 4 | m_words.resize_and_keep_capacity(2); |
53 | 4 | m_words[0] = static_cast<Word>(value & 0xFFFFFFFF); |
54 | 4 | m_words[1] = static_cast<Word>((value >> 32) & 0xFFFFFFFF); |
55 | 4 | } |
56 | | |
57 | 68.5k | UnsignedBigInteger() = default; |
58 | | |
59 | | [[nodiscard]] static UnsignedBigInteger create_invalid(); |
60 | | |
61 | 0 | [[nodiscard]] static UnsignedBigInteger import_data(StringView data) { return import_data((u8 const*)data.characters_without_null_termination(), data.length()); } |
62 | | [[nodiscard]] static UnsignedBigInteger import_data(u8 const* ptr, size_t length) |
63 | 7.67k | { |
64 | 7.67k | return UnsignedBigInteger(ptr, length); |
65 | 7.67k | } |
66 | | |
67 | | size_t export_data(Bytes, bool remove_leading_zeros = false) const; |
68 | | |
69 | | [[nodiscard]] static ErrorOr<UnsignedBigInteger> from_base(u16 N, StringView str); |
70 | | [[nodiscard]] ErrorOr<String> to_base(u16 N) const; |
71 | | [[nodiscard]] ByteString to_base_deprecated(u16 N) const; |
72 | | |
73 | | [[nodiscard]] u64 to_u64() const; |
74 | | |
75 | | enum class RoundingMode { |
76 | | IEEERoundAndTiesToEvenMantissa, |
77 | | RoundTowardZero, |
78 | | // “the Number value for x”, https://tc39.es/ecma262/#number-value-for |
79 | | ECMAScriptNumberValueFor = IEEERoundAndTiesToEvenMantissa, |
80 | | }; |
81 | | |
82 | | [[nodiscard]] double to_double(RoundingMode rounding_mode = RoundingMode::IEEERoundAndTiesToEvenMantissa) const; |
83 | | |
84 | 2.18k | [[nodiscard]] Vector<Word, STARTING_WORD_SIZE> const& words() const { return m_words; } |
85 | | |
86 | | void set_to_0(); |
87 | | void set_to(Word other); |
88 | | void set_to(UnsignedBigInteger const& other); |
89 | | |
90 | | void invalidate() |
91 | 0 | { |
92 | 0 | m_is_invalid = true; |
93 | 0 | m_cached_trimmed_length = {}; |
94 | 0 | m_cached_hash = 0; |
95 | 0 | } |
96 | | |
97 | | [[nodiscard]] bool is_zero() const; |
98 | 0 | [[nodiscard]] bool is_odd() const { return m_words.size() && (m_words[0] & 1); } |
99 | 7.99k | [[nodiscard]] bool is_invalid() const { return m_is_invalid; } |
100 | | |
101 | 680k | [[nodiscard]] size_t length() const { return m_words.size(); } |
102 | | // The "trimmed length" is the number of words after trimming leading zeroed words |
103 | | [[nodiscard]] size_t trimmed_length() const; |
104 | | |
105 | 0 | [[nodiscard]] size_t byte_length() const { return length() * sizeof(Word); } |
106 | 0 | [[nodiscard]] size_t trimmed_byte_length() const { return trimmed_length() * sizeof(Word); } |
107 | | |
108 | | void clamp_to_trimmed_length(); |
109 | | void resize_with_leading_zeros(size_t num_words); |
110 | | |
111 | | size_t one_based_index_of_highest_set_bit() const; |
112 | | |
113 | | [[nodiscard]] UnsignedBigInteger plus(UnsignedBigInteger const& other) const; |
114 | | [[nodiscard]] UnsignedBigInteger minus(UnsignedBigInteger const& other) const; |
115 | | [[nodiscard]] UnsignedBigInteger bitwise_or(UnsignedBigInteger const& other) const; |
116 | | [[nodiscard]] UnsignedBigInteger bitwise_and(UnsignedBigInteger const& other) const; |
117 | | [[nodiscard]] UnsignedBigInteger bitwise_xor(UnsignedBigInteger const& other) const; |
118 | | [[nodiscard]] UnsignedBigInteger bitwise_not_fill_to_one_based_index(size_t) const; |
119 | | [[nodiscard]] UnsignedBigInteger shift_left(size_t num_bits) const; |
120 | | [[nodiscard]] UnsignedBigInteger shift_right(size_t num_bits) const; |
121 | | [[nodiscard]] UnsignedBigInteger multiplied_by(UnsignedBigInteger const& other) const; |
122 | | [[nodiscard]] UnsignedDivisionResult divided_by(UnsignedBigInteger const& divisor) const; |
123 | | |
124 | | [[nodiscard]] u32 hash() const; |
125 | | |
126 | | void set_bit_inplace(size_t bit_index); |
127 | | |
128 | | [[nodiscard]] bool operator==(UnsignedBigInteger const& other) const; |
129 | | [[nodiscard]] bool operator!=(UnsignedBigInteger const& other) const; |
130 | | [[nodiscard]] bool operator<(UnsignedBigInteger const& other) const; |
131 | | [[nodiscard]] bool operator>(UnsignedBigInteger const& other) const; |
132 | | [[nodiscard]] bool operator>=(UnsignedBigInteger const& other) const; |
133 | | |
134 | | enum class CompareResult { |
135 | | DoubleEqualsBigInt, |
136 | | DoubleLessThanBigInt, |
137 | | DoubleGreaterThanBigInt |
138 | | }; |
139 | | |
140 | | [[nodiscard]] CompareResult compare_to_double(double) const; |
141 | | |
142 | | private: |
143 | | friend class UnsignedBigIntegerAlgorithms; |
144 | | |
145 | | // Little endian |
146 | | // m_word[0] + m_word[1] * Word::MAX + m_word[2] * Word::MAX * Word::MAX + ... |
147 | | Vector<Word, STARTING_WORD_SIZE> m_words; |
148 | 0 | StorageSpan words_span() { return { m_words.data(), m_words.size() }; } |
149 | | ConstStorageSpan words_span() const |
150 | 0 | { |
151 | 0 | return { m_words.data(), m_words.size() }; |
152 | 0 | } |
153 | | |
154 | | mutable u32 m_cached_hash { 0 }; |
155 | | |
156 | | // Used to indicate a negative result, or a result of an invalid operation |
157 | | bool m_is_invalid { false }; |
158 | | |
159 | | mutable Optional<size_t> m_cached_trimmed_length; |
160 | | }; |
161 | | |
162 | | struct UnsignedDivisionResult { |
163 | | Crypto::UnsignedBigInteger quotient; |
164 | | Crypto::UnsignedBigInteger remainder; |
165 | | }; |
166 | | |
167 | | } |
168 | | |
169 | | template<> |
170 | | struct AK::Formatter<Crypto::UnsignedBigInteger> : Formatter<StringView> { |
171 | | ErrorOr<void> format(FormatBuilder&, Crypto::UnsignedBigInteger const&); |
172 | | }; |
173 | | |
174 | | inline Crypto::UnsignedBigInteger |
175 | | operator""_bigint(char const* string, size_t length) |
176 | 0 | { |
177 | 0 | return MUST(Crypto::UnsignedBigInteger::from_base(10, { string, length })); |
178 | 0 | } Unexecuted instantiation: operator"" _bigint(char const*, unsigned long) Unexecuted instantiation: operator"" _bigint(char const*, unsigned long) |