/src/serenity/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, the SerenityOS developers. |
3 | | * Copyright (c) 2022, David Tuin <davidot@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/Concepts.h> |
11 | | #include <AK/Span.h> |
12 | | #include <AK/String.h> |
13 | | #include <LibCrypto/BigInt/UnsignedBigInteger.h> |
14 | | |
15 | | namespace Crypto { |
16 | | |
17 | | struct SignedDivisionResult; |
18 | | |
19 | | class SignedBigInteger { |
20 | | public: |
21 | | template<Signed T> |
22 | | requires(sizeof(T) <= sizeof(i32)) |
23 | | SignedBigInteger(T value) |
24 | 12 | : m_sign(value < 0) |
25 | 12 | , m_unsigned_data(static_cast<u32>(abs(static_cast<i64>(value)))) |
26 | 12 | { |
27 | 12 | } |
28 | | |
29 | | SignedBigInteger(UnsignedBigInteger&& unsigned_data, bool sign) |
30 | 80 | : m_sign(sign) |
31 | 80 | , m_unsigned_data(move(unsigned_data)) |
32 | 80 | { |
33 | 80 | ensure_sign_is_valid(); |
34 | 80 | } |
35 | | |
36 | | explicit SignedBigInteger(UnsignedBigInteger unsigned_data) |
37 | 0 | : m_sign(false) |
38 | 0 | , m_unsigned_data(move(unsigned_data)) |
39 | 0 | { |
40 | 0 | } |
41 | | |
42 | | SignedBigInteger() |
43 | 0 | : m_sign(false) |
44 | 0 | , m_unsigned_data() |
45 | 0 | { |
46 | 0 | } |
47 | | |
48 | | explicit SignedBigInteger(double value); |
49 | | |
50 | | explicit SignedBigInteger(i64 value) |
51 | 2 | : m_sign(value < 0) |
52 | 2 | , m_unsigned_data(value < 0 ? static_cast<u64>(-(value + 1)) + 1 : static_cast<u64>(value)) |
53 | 2 | { |
54 | 2 | } |
55 | | |
56 | | [[nodiscard]] static SignedBigInteger create_invalid() |
57 | 0 | { |
58 | 0 | return { UnsignedBigInteger::create_invalid(), false }; |
59 | 0 | } |
60 | | |
61 | 0 | [[nodiscard]] static SignedBigInteger import_data(StringView data) { return import_data((u8 const*)data.characters_without_null_termination(), data.length()); } |
62 | | [[nodiscard]] static SignedBigInteger import_data(u8 const* ptr, size_t length); |
63 | | |
64 | | size_t export_data(Bytes, bool remove_leading_zeros = false) const; |
65 | | |
66 | | [[nodiscard]] static ErrorOr<SignedBigInteger> from_base(u16 N, StringView str); |
67 | | [[nodiscard]] ErrorOr<String> to_base(u16 N) const; |
68 | | [[nodiscard]] ByteString to_base_deprecated(u16 N) const; |
69 | | |
70 | | [[nodiscard]] u64 to_u64() const; |
71 | | [[nodiscard]] double to_double(UnsignedBigInteger::RoundingMode rounding_mode = UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa) const; |
72 | | |
73 | 0 | [[nodiscard]] UnsignedBigInteger const& unsigned_value() const { return m_unsigned_data; } |
74 | 0 | [[nodiscard]] Vector<u32, STARTING_WORD_SIZE> const words() const { return m_unsigned_data.words(); } |
75 | 0 | [[nodiscard]] bool is_positive() const { return !is_negative() && !is_zero(); } |
76 | 0 | [[nodiscard]] bool is_negative() const { return m_sign; } |
77 | 0 | [[nodiscard]] bool is_zero() const { return m_unsigned_data.is_zero(); } |
78 | | |
79 | | void negate() |
80 | 0 | { |
81 | 0 | if (!m_unsigned_data.is_zero()) |
82 | 0 | m_sign = !m_sign; |
83 | 0 | } |
84 | | |
85 | | void set_to_0() |
86 | 0 | { |
87 | 0 | m_unsigned_data.set_to_0(); |
88 | 0 | m_sign = false; |
89 | 0 | } |
90 | | |
91 | | void set_to(i32 other) |
92 | 0 | { |
93 | 0 | m_unsigned_data.set_to((u32)other); |
94 | 0 | m_sign = other < 0; |
95 | 0 | } |
96 | | void set_to(SignedBigInteger const& other) |
97 | 0 | { |
98 | 0 | m_unsigned_data.set_to(other.m_unsigned_data); |
99 | 0 | m_sign = other.m_sign; |
100 | 0 | } |
101 | | |
102 | | void invalidate() |
103 | 0 | { |
104 | 0 | m_unsigned_data.invalidate(); |
105 | 0 | } |
106 | | |
107 | 0 | [[nodiscard]] bool is_invalid() const { return m_unsigned_data.is_invalid(); } |
108 | | |
109 | | // These get + 1 byte for the sign. |
110 | 0 | [[nodiscard]] size_t length() const { return m_unsigned_data.length() + 1; } |
111 | 0 | [[nodiscard]] size_t trimmed_length() const { return m_unsigned_data.trimmed_length() + 1; } |
112 | | |
113 | | [[nodiscard]] SignedBigInteger plus(SignedBigInteger const& other) const; |
114 | | [[nodiscard]] SignedBigInteger minus(SignedBigInteger const& other) const; |
115 | | [[nodiscard]] SignedBigInteger bitwise_or(SignedBigInteger const& other) const; |
116 | | [[nodiscard]] SignedBigInteger bitwise_and(SignedBigInteger const& other) const; |
117 | | [[nodiscard]] SignedBigInteger bitwise_xor(SignedBigInteger const& other) const; |
118 | | [[nodiscard]] SignedBigInteger bitwise_not() const; |
119 | | [[nodiscard]] SignedBigInteger shift_left(size_t num_bits) const; |
120 | | [[nodiscard]] SignedBigInteger shift_right(size_t num_bits) const; |
121 | | [[nodiscard]] SignedBigInteger multiplied_by(SignedBigInteger const& other) const; |
122 | | [[nodiscard]] SignedDivisionResult divided_by(SignedBigInteger const& divisor) const; |
123 | | |
124 | | [[nodiscard]] SignedBigInteger plus(UnsignedBigInteger const& other) const; |
125 | | [[nodiscard]] SignedBigInteger minus(UnsignedBigInteger const& other) const; |
126 | | [[nodiscard]] SignedBigInteger multiplied_by(UnsignedBigInteger const& other) const; |
127 | | [[nodiscard]] SignedDivisionResult divided_by(UnsignedBigInteger const& divisor) const; |
128 | | |
129 | | [[nodiscard]] SignedBigInteger negated_value() const; |
130 | | |
131 | | [[nodiscard]] u32 hash() const; |
132 | | |
133 | | void set_bit_inplace(size_t bit_index); |
134 | | |
135 | | [[nodiscard]] bool operator==(SignedBigInteger const& other) const; |
136 | | [[nodiscard]] bool operator!=(SignedBigInteger const& other) const; |
137 | | [[nodiscard]] bool operator<(SignedBigInteger const& other) const; |
138 | | [[nodiscard]] bool operator<=(SignedBigInteger const& other) const; |
139 | | [[nodiscard]] bool operator>(SignedBigInteger const& other) const; |
140 | | [[nodiscard]] bool operator>=(SignedBigInteger const& other) const; |
141 | | |
142 | | [[nodiscard]] bool operator==(UnsignedBigInteger const& other) const; |
143 | | [[nodiscard]] bool operator!=(UnsignedBigInteger const& other) const; |
144 | | [[nodiscard]] bool operator<(UnsignedBigInteger const& other) const; |
145 | | [[nodiscard]] bool operator>(UnsignedBigInteger const& other) const; |
146 | | |
147 | | [[nodiscard]] UnsignedBigInteger::CompareResult compare_to_double(double) const; |
148 | | |
149 | | private: |
150 | | void ensure_sign_is_valid() |
151 | 80 | { |
152 | 80 | if (m_sign && m_unsigned_data.is_zero()) |
153 | 0 | m_sign = false; |
154 | 80 | } |
155 | | |
156 | | bool m_sign { false }; |
157 | | UnsignedBigInteger m_unsigned_data; |
158 | | }; |
159 | | |
160 | | struct SignedDivisionResult { |
161 | | Crypto::SignedBigInteger quotient; |
162 | | Crypto::SignedBigInteger remainder; |
163 | | }; |
164 | | |
165 | | } |
166 | | |
167 | | template<> |
168 | | struct AK::Formatter<Crypto::SignedBigInteger> : AK::Formatter<Crypto::UnsignedBigInteger> { |
169 | | ErrorOr<void> format(FormatBuilder&, Crypto::SignedBigInteger const&); |
170 | | }; |
171 | | |
172 | | inline Crypto::SignedBigInteger |
173 | | operator""_sbigint(char const* string, size_t length) |
174 | 80 | { |
175 | 80 | return MUST(Crypto::SignedBigInteger::from_base(10, { string, length })); |
176 | 80 | } |