Coverage Report

Created: 2026-07-25 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibCrypto/Curves/Curve25519.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2022, stelar7 <dudedbz@gmail.com>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Endian.h>
8
#include <AK/Types.h>
9
#include <LibCrypto/Curves/Curve25519.h>
10
11
namespace Crypto::Curves {
12
13
void Curve25519::set(u32* state, u32 value)
14
0
{
15
0
    state[0] = value;
16
17
0
    for (auto i = 1; i < WORDS; i++) {
18
0
        state[i] = 0;
19
0
    }
20
0
}
21
22
void Curve25519::modular_square(u32* state, u32 const* value)
23
0
{
24
    // Compute R = (A ^ 2) mod p
25
0
    modular_multiply(state, value, value);
26
0
}
27
28
void Curve25519::modular_subtract(u32* state, u32 const* first, u32 const* second)
29
0
{
30
    // R = (A - B) mod p
31
0
    i64 temp = -19;
32
0
    for (auto i = 0; i < WORDS; i++) {
33
0
        temp += first[i];
34
0
        temp -= second[i];
35
0
        state[i] = temp & 0xFFFFFFFF;
36
0
        temp >>= 32;
37
0
    }
38
39
    // Compute R = A + (2^255 - 19) - B
40
0
    state[7] += 0x80000000;
41
42
0
    modular_reduce(state, state);
43
0
}
44
45
void Curve25519::modular_add(u32* state, u32 const* first, u32 const* second)
46
0
{
47
    // R = (A + B) mod p
48
0
    u64 temp = 0;
49
0
    for (auto i = 0; i < WORDS; i++) {
50
0
        temp += first[i];
51
0
        temp += second[i];
52
0
        state[i] = temp & 0xFFFFFFFF;
53
0
        temp >>= 32;
54
0
    }
55
56
0
    modular_reduce(state, state);
57
0
}
58
59
void Curve25519::modular_multiply(u32* state, u32 const* first, u32 const* second)
60
0
{
61
    // Compute R = (A * B) mod p
62
0
    u64 temp = 0;
63
0
    u64 carry = 0;
64
0
    u32 output[WORDS * 2];
65
66
    // Comba's method
67
0
    for (auto i = 0; i < 16; i++) {
68
0
        if (i < WORDS) {
69
0
            for (auto j = 0; j <= i; j++) {
70
0
                temp += (u64)first[j] * second[i - j];
71
0
                carry += temp >> 32;
72
0
                temp &= 0xFFFFFFFF;
73
0
            }
74
0
        } else {
75
0
            for (auto j = i - 7; j < WORDS; j++) {
76
0
                temp += (u64)first[j] * second[i - j];
77
0
                carry += temp >> 32;
78
0
                temp &= 0xFFFFFFFF;
79
0
            }
80
0
        }
81
82
0
        output[i] = temp & 0xFFFFFFFF;
83
0
        temp = carry & 0xFFFFFFFF;
84
0
        carry >>= 32;
85
0
    }
86
87
    // Reduce bit 255 (2^255 = 19 mod p)
88
0
    temp = (output[7] >> 31) * 19;
89
    // Mask the most significant bit
90
0
    output[7] &= 0x7FFFFFFF;
91
92
    // Fast modular reduction 1st pass
93
0
    for (auto i = 0; i < WORDS; i++) {
94
0
        temp += output[i];
95
0
        temp += (u64)output[i + 8] * 38;
96
0
        output[i] = temp & 0xFFFFFFFF;
97
0
        temp >>= 32;
98
0
    }
99
100
    // Reduce bit 256 (2^256 = 38 mod p)
101
0
    temp *= 38;
102
    // Reduce bit 255 (2^255 = 19 mod p)
103
0
    temp += (output[7] >> 31) * 19;
104
    // Mask the most significant bit
105
0
    output[7] &= 0x7FFFFFFF;
106
107
    // Fast modular reduction 2nd pass
108
0
    for (auto i = 0; i < WORDS; i++) {
109
0
        temp += output[i];
110
0
        output[i] = temp & 0xFFFFFFFF;
111
0
        temp >>= 32;
112
0
    }
113
114
0
    modular_reduce(state, output);
115
0
}
116
117
void Curve25519::export_state(u32* state, u8* output)
118
0
{
119
0
    for (u32 i = 0; i < WORDS; i++) {
120
0
        state[i] = AK::convert_between_host_and_little_endian(state[i]);
121
0
    }
122
123
0
    memcpy(output, state, BYTES);
124
0
}
125
126
void Curve25519::import_state(u32* state, u8 const* data)
127
0
{
128
0
    memcpy(state, data, BYTES);
129
0
    for (u32 i = 0; i < WORDS; i++) {
130
0
        state[i] = AK::convert_between_host_and_little_endian(state[i]);
131
0
    }
132
0
}
133
134
void Curve25519::modular_subtract_single(u32* r, u32 const* a, u32 b)
135
0
{
136
0
    i64 temp = -19;
137
0
    temp -= b;
138
139
    // Compute R = A - 19 - B
140
0
    for (u32 i = 0; i < 8; i++) {
141
0
        temp += a[i];
142
0
        r[i] = temp & 0xFFFFFFFF;
143
0
        temp >>= 32;
144
0
    }
145
146
    // Compute R = A + (2^255 - 19) - B
147
0
    r[7] += 0x80000000;
148
0
    modular_reduce(r, r);
149
0
}
150
151
void Curve25519::modular_add_single(u32* state, u32 const* first, u32 second)
152
0
{
153
0
    u64 temp = second;
154
155
    // Compute R = A + B
156
0
    for (u32 i = 0; i < 8; i++) {
157
0
        temp += first[i];
158
0
        state[i] = temp & 0xFFFFFFFF;
159
0
        temp >>= 32;
160
0
    }
161
162
0
    modular_reduce(state, state);
163
0
}
164
165
u32 Curve25519::modular_square_root(u32* r, u32 const* a, u32 const* b)
166
0
{
167
0
    u32 c[8];
168
0
    u32 u[8];
169
0
    u32 v[8];
170
171
    // To compute the square root of (A / B), the first step is to compute the candidate root x = (A / B)^((p+3)/8)
172
0
    modular_square(v, b);
173
0
    modular_multiply(v, v, b);
174
0
    modular_square(v, v);
175
0
    modular_multiply(v, v, b);
176
0
    modular_multiply(c, a, v);
177
0
    modular_square(u, c);
178
0
    modular_multiply(u, u, c);
179
0
    modular_square(u, u);
180
0
    modular_multiply(v, u, c);
181
0
    to_power_of_2n(u, v, 3);
182
0
    modular_multiply(u, u, v);
183
0
    modular_square(u, u);
184
0
    modular_multiply(v, u, c);
185
0
    to_power_of_2n(u, v, 7);
186
0
    modular_multiply(u, u, v);
187
0
    modular_square(u, u);
188
0
    modular_multiply(v, u, c);
189
0
    to_power_of_2n(u, v, 15);
190
0
    modular_multiply(u, u, v);
191
0
    modular_square(u, u);
192
0
    modular_multiply(v, u, c);
193
0
    to_power_of_2n(u, v, 31);
194
0
    modular_multiply(v, u, v);
195
0
    to_power_of_2n(u, v, 62);
196
0
    modular_multiply(u, u, v);
197
0
    modular_square(u, u);
198
0
    modular_multiply(v, u, c);
199
0
    to_power_of_2n(u, v, 125);
200
0
    modular_multiply(u, u, v);
201
0
    modular_square(u, u);
202
0
    modular_square(u, u);
203
0
    modular_multiply(u, u, c);
204
205
    // The first candidate root is U = A * B^3 * (A * B^7)^((p - 5) / 8)
206
0
    modular_multiply(u, u, a);
207
0
    modular_square(v, b);
208
0
    modular_multiply(v, v, b);
209
0
    modular_multiply(u, u, v);
210
211
    // The second candidate root is V = U * sqrt(-1)
212
0
    modular_multiply(v, u, SQRT_MINUS_1);
213
214
0
    modular_square(c, u);
215
0
    modular_multiply(c, c, b);
216
217
    // Check whether B * U^2 = A
218
0
    u32 first_comparison = compare(c, a);
219
220
0
    modular_square(c, v);
221
0
    modular_multiply(c, c, b);
222
223
    // Check whether B * V^2 = A
224
0
    u32 second_comparison = compare(c, a);
225
226
    // Select the first or the second candidate root
227
0
    select(r, u, v, first_comparison);
228
229
    // Return 0 if the square root exists
230
0
    return first_comparison & second_comparison;
231
0
}
232
233
u32 Curve25519::compare(u32 const* a, u32 const* b)
234
0
{
235
0
    u32 mask = 0;
236
0
    for (u32 i = 0; i < 8; i++) {
237
0
        mask |= a[i] ^ b[i];
238
0
    }
239
240
    // Return 0 if A = B, else 1
241
0
    return ((u32)(mask | (~mask + 1))) >> 31;
242
0
}
243
244
void Curve25519::modular_reduce(u32* state, u32 const* data)
245
0
{
246
    // R = A mod p
247
0
    u64 temp = 19;
248
0
    u32 other[WORDS];
249
250
0
    for (auto i = 0; i < WORDS; i++) {
251
0
        temp += data[i];
252
0
        other[i] = temp & 0xFFFFFFFF;
253
0
        temp >>= 32;
254
0
    }
255
256
    // Compute B = A - (2^255 - 19)
257
0
    other[7] -= 0x80000000;
258
259
0
    u32 mask = (other[7] & 0x80000000) >> 31;
260
0
    select(state, other, data, mask);
261
0
}
262
263
void Curve25519::to_power_of_2n(u32* state, u32 const* value, u8 n)
264
0
{
265
    // Pre-compute (A ^ 2) mod p
266
0
    modular_square(state, value);
267
268
    // Compute R = (A ^ (2^n)) mod p
269
0
    for (u32 i = 1; i < n; i++) {
270
0
        modular_square(state, state);
271
0
    }
272
0
}
273
274
void Curve25519::select(u32* state, u32 const* a, u32 const* b, u32 condition)
275
0
{
276
    // If B < (2^255 - 19) then R = B, else R = A
277
0
    u32 mask = condition - 1;
278
279
0
    for (auto i = 0; i < WORDS; i++) {
280
0
        state[i] = (a[i] & mask) | (b[i] & ~mask);
281
0
    }
282
0
}
283
284
void Curve25519::copy(u32* state, u32 const* value)
285
0
{
286
0
    for (auto i = 0; i < WORDS; i++) {
287
0
        state[i] = value[i];
288
0
    }
289
0
}
290
291
void Curve25519::modular_multiply_inverse(u32* state, u32 const* value)
292
0
{
293
    // Compute R = A^-1 mod p
294
0
    u32 u[WORDS];
295
0
    u32 v[WORDS];
296
297
    // Fermat's little theorem
298
0
    modular_square(u, value);
299
0
    modular_multiply(u, u, value);
300
0
    modular_square(u, u);
301
0
    modular_multiply(v, u, value);
302
0
    to_power_of_2n(u, v, 3);
303
0
    modular_multiply(u, u, v);
304
0
    modular_square(u, u);
305
0
    modular_multiply(v, u, value);
306
0
    to_power_of_2n(u, v, 7);
307
0
    modular_multiply(u, u, v);
308
0
    modular_square(u, u);
309
0
    modular_multiply(v, u, value);
310
0
    to_power_of_2n(u, v, 15);
311
0
    modular_multiply(u, u, v);
312
0
    modular_square(u, u);
313
0
    modular_multiply(v, u, value);
314
0
    to_power_of_2n(u, v, 31);
315
0
    modular_multiply(v, u, v);
316
0
    to_power_of_2n(u, v, 62);
317
0
    modular_multiply(u, u, v);
318
0
    modular_square(u, u);
319
0
    modular_multiply(v, u, value);
320
0
    to_power_of_2n(u, v, 125);
321
0
    modular_multiply(u, u, v);
322
0
    modular_square(u, u);
323
0
    modular_square(u, u);
324
0
    modular_multiply(u, u, value);
325
0
    modular_square(u, u);
326
0
    modular_square(u, u);
327
0
    modular_multiply(u, u, value);
328
0
    modular_square(u, u);
329
0
    modular_multiply(state, u, value);
330
0
}
331
332
void Curve25519::modular_multiply_single(u32* state, u32 const* first, u32 second)
333
0
{
334
    // Compute R = (A * B) mod p
335
0
    u64 temp = 0;
336
0
    u32 output[WORDS];
337
338
0
    for (auto i = 0; i < WORDS; i++) {
339
0
        temp += (u64)first[i] * second;
340
0
        output[i] = temp & 0xFFFFFFFF;
341
0
        temp >>= 32;
342
0
    }
343
344
    // Reduce bit 256 (2^256 = 38 mod p)
345
0
    temp *= 38;
346
    // Reduce bit 255 (2^255 = 19 mod p)
347
0
    temp += (output[7] >> 31) * 19;
348
    // Mask the most significant bit
349
0
    output[7] &= 0x7FFFFFFF;
350
351
    // Fast modular reduction
352
0
    for (auto i = 0; i < WORDS; i++) {
353
0
        temp += output[i];
354
0
        output[i] = temp & 0xFFFFFFFF;
355
0
        temp >>= 32;
356
0
    }
357
358
0
    modular_reduce(state, output);
359
0
}
360
}