Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}