Coverage Report

Created: 2026-05-16 07:03

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