1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
*******************************************************************************
\file pri.h
\brief Primes
\project bee2 [cryptographic library]
\created 2012.08.13
\version 2025.04.25
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/
/*!
*******************************************************************************
\file pri.h
\brief Простые числа
*******************************************************************************
*/
#ifndef __BEE2_PRI_H
#define __BEE2_PRI_H
#include "bee2/defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
*******************************************************************************
\file pri.h
Реализована проверка простоты натуральных чисел и построение больших простых.
Числа представляются по правилам zz.h.
Используется факторная база, составленная из первых нечетных простых.
\pre Все входные указатели действительны.
\pre Вспомогательный буфер stack не пересекается с другими буферами.
\safe todo
*******************************************************************************
*/
/*
*******************************************************************************
Факторная база
*******************************************************************************
*/
/*! \brief Размер факторной базы
Возвращается число элементов факторной базы, т.е. число поддерживаемых
первых нечетных простых.
\return Размер факторной базы.
*/
size_t priBaseSize();
/*! \brief Простое из факторной базы
Определяется i-й элемент факторной базы, т.е. (i + 1)-ое нечетное
простое число.
\pre i < priBaseSize().
\return Элемент факторной базы.
*/
word priBasePrime(
size_t i /*!< [in] номер */
);
/*! \brief Остатки от деления на простые из факторной базы
Определяются остатки [count]mods от деления числа [n]a на первые count
простых из факторной базы.
\pre count <= priBaseSize().
*/
void priBaseMod(
word mods[], /*!< [out] остатки */
const word a[], /*!< [in] число */
size_t n, /*!< [in] длина a в машинных словах */
size_t count /*!< [in] число остатков */
);
/*
*******************************************************************************
Использование факторной базы
*******************************************************************************
*/
/*! \brief Просеянное?
Проверяется что число [n]a является просеянным: a -- нечетное и не делится
на base_count первых простых из факторной базы.
\pre base_count <= priBaseSize().
\return Признак успеха.
\remark Число a не считается просеянным, если совпадает с элементом
факторной базы. Число a = 1 считается просеянным.
\deep{stack} priIsSieved_deep(n).
\safe Функция нерегулярна.
*/
bool_t priIsSieved(
const word a[], /*!< [in] проверяемое число */
size_t n, /*!< [in] длина a в машинных словах */
size_t base_count, /*!< [in] число элементов факторной базы */
void* stack /*!< [in] вспомогательная память */
);
size_t priIsSieved_deep(size_t base_count);
/*! \brief Гладкое?
Проверяется что число [n]a является гладким: a делится только на 2
и на base_count первых простых из факторной базы.
\pre base_count <= priBaseSize().
\return Признак успеха.
\remark Число a не считается , если совпадает с элементом
факторной базы. Число a = 1 считается просеянным.
\deep{stack} priIsSmooth_deep(n).
*/
bool_t priIsSmooth(
const word a[], /*!< [in] проверяемое число */
size_t n, /*!< [in] длина a в машинных словах */
size_t base_count, /*!< [in] число элементов факторной базы */
void* stack /*!< [in] вспомогательная память */
);
size_t priIsSmooth_deep(size_t n);
/*
*******************************************************************************
Проверка простоты
*******************************************************************************
*/
/*! \brief Простое машинное слово?
Проверяется что число a, которое укладывается в машинное слово, является
простым.
\return Признак простоты.
\remark Реализован детерминированный тест (без ошибок).
\deep{stack} priIsPrimeW_deep().
*/
bool_t priIsPrimeW(
register word a, /*!< [in] проверяемое число */
void* stack /*!< [in] вспомогательная память */
);
size_t priIsPrimeW_deep();
/*! \brief Тест Рабина -- Миллера
С помощью теста Рабина -- Миллера проверяется, что число [n]a
является простым. Выполняется iter итераций теста.
\return Признак простоты.
\remark Тест является вероятностным и возможны ошибки. Вероятность
признания простым составного числа не превосходит 1 / 4^iter.
Простое может быть признано составным, если за большое число попыток
не удается построить случайное число из множества {1, 2,.., a - 1}
без двух элементов. Вероятность последнего события не превосходит
1 / 2^B_PER_IMPOSSIBLE.
\remark При iter == 0 простым будет признано всякое нечетное число,
большее 7.
\deep{stack} priRMTest_deep(n).
*/
bool_t priRMTest(
const word a[], /*!< [in] проверяемое число */
size_t n, /*!< [in] длина a в машинных словах */
size_t iter, /*!< [in] число итераций */
void* stack /*!< [in] вспомогательная память */
);
size_t priRMTest_deep(size_t n);
/*! \brief Простое?
Проверяется, что число [n]a является простым. Используется
тест Рабина -- Миллера с числом итераций B_PER_IMPOSSIBLE / 2.
\return Признак простоты.
\remark Вероятность ошибки не превосходит 1 / 2^B_PER_IMPOSSIBLE.
\deep{stack} priIsPrime_deep(n).
*/
bool_t priIsPrime(
const word a[], /*!< [in] проверяемое число */
size_t n, /*!< [in] длина a в машинных словах */
void* stack /*!< [in] вспомогательная память */
);
size_t priIsPrime_deep(size_t n);
/*! \brief Простое Софи Жермен?
Проверяется, что нечетное простое число [n]q является простым Софи Жермен,
т.е. что 2q + 1 также простое.
\pre q -- нечетное && q > 1.
\expect q -- простое.
\return Признак успеха.
\remark Реализован детерминированный тест (без ошибок).
\deep{stack} priIsSGPrime_deep(n).
*/
bool_t priIsSGPrime(
const word q[], /*!< [in] проверяемое простое число */
size_t n, /*!< [in] длина q в машинных словах */
void* stack /*!< [in] вспомогательная память */
);
size_t priIsSGPrime_deep(size_t n);
/*
*******************************************************************************
Генерация простых
*******************************************************************************
*/
/*! \brief Следующее малое простое
Определяется минимальное нечетное простое p из интервала [a, 2^l),
где l -- битовая длина a.
\return Признак успеха.
*/
bool_t priNextPrimeW(
word p[1], /*!< [out] простое число */
word a, /*!< [in] начальное значение */
void* stack /*!< [in] вспомогательная память */
);
size_t priNextPrimeW_deep();
/*! \brief Следующее простое
Определяется минимальное нечетное простое [n]p из интервала [[n]a, 2^l),
где l -- битовая длина a. Проверяются на простоту trials первых
чисел-кандидатов (или все возможные кандидаты при trials == SIZE_MAX).
Сначала проверяется, что кандидат не делится на base_count простых из
факторной базы. Затем применяется тест Рабина -- Миллера с iter итерациями.
\pre Буфер p либо не пересекается с буфером a, либо указатели a и p
совпадают.
\pre base_count <= priBaseSize().
\return TRUE, если искомое простое найдено, и FALSE в противном случае.
\deep{stack} priNextPrime_deep(n, base_count).
*/
bool_t priNextPrime(
word p[], /*!< [out] простое число */
const word a[], /*!< [in] начальное значение */
size_t n, /*!< [in] длина a и p в машинных словах */
size_t trials, /*!< [in] число кандидатов */
size_t base_count, /*!< [in] число элементов факторной базы */
size_t iter, /*!< [in] число итераций теста Рабина -- Миллера */
void* stack /*!< [in] вспомогательная память */
);
size_t priNextPrime_deep(size_t n, size_t base_count);
/*! \brief Расширение простого
По базовому нечетному простому [n]q строится расширенное
простое [W_OF_B(l)]p битовой длины l, которое имеет вид 2 * q * r + 1.
Число r строится с помощью генератора rng с состоянием rng_state.
Простота построенного числа p проверяется в два этапа. Сначала
проверяется, что p не делится на base_count простых из факторной
базы. Затем проверяется условие теоремы Демитко. Если число p не подходит,
то оно увеличивается на 2 и проверка повторяется. Если при увеличении p
его битовая длина становится больше l, то генерируется новое r,
затем p пересчитывается. Всего используется не более trials кандидатов p.
\pre Буфер p не пересекается с буфером q.
\pre n > 0 && q[n - 1] != 0.
\pre q -- нечетное && q >= 3.
\pre wwBitSize(q, n) + 1 <= l && l <= 2 * wwBitSize(q, n).
\pre base_count <= priBaseSize().
\expect q -- простое.
\return TRUE, если искомое простое найдено, и FALSE в противном случае.
\remark При trials == SIZE_MAX проверяются все возможные кандидаты.
\remark Для применения теоремы Демитко требуется выполнение условия
2 * r < 4 * q + 1. Ограничение l <= 2 * wwBitSize(q, n) гарантирует
выполнение этого условия.
\deep{stack} priExtendPrime_deep(l, n, base_count).
*/
bool_t priExtendPrime(
word p[], /*!< [out] расширенное простое число */
size_t l, /*!< [in] длина p в битах */
const word q[], /*!< [in] базовое простое число */
size_t n, /*!< [in] длина q в машинных словах */
size_t trials, /*!< [in] число кандидатов */
size_t base_count, /*!< [in] число элементов факторной базы */
gen_i rng, /*!< [in] генератор случайных чисел */
void* rng_state, /*!< [in] состояние rng */
void* stack /*!< [in] вспомогательная память */
);
size_t priExtendPrime_deep(size_t l, size_t n, size_t base_count);
/*! \brief Расширение простого с условием делимости
По базовому нечетному простому [n]q и неотрицательному [m]a строится
расширенное простое [W_OF_B(l)]p битовой длины l, которое имеет вид
2 * q * a * r + 1. Число r строится с помощью генератора rng с состоянием
rng_state. Простота p проверяется так же, как в функции priExtendPrime().
Используется base_count простых из факторной базы, используется не более
trials кандидатов p.
\pre Буфер p не пересекается с буфером q.
\pre n > 0 && q[n - 1] != 0 && m > 0 && a[m - 1] != 0.
\pre q -- нечетное && q >= 3.
\pre wwBitSize(q * a, n + m) + 1 <= l.
\pre l <= 2 * wwBitSize(q, n).
\pre base_count <= priBaseSize().
\expect q -- простое.
\return TRUE, если искомое простое найдено, и FALSE в противном случае.
\remark При trials == SIZE_MAX проверяются все возможные кандидаты.
\remark Для применения теоремы Демитко требуется выполнение условия
2 * a * r < 4 * q + 1. Ограничение l <= 2 * wwBitSize(q, n) гарантирует
выполнение этого условия.
\deep{stack} priExtendPrime2_deep(l, n, m, base_count).
*/
bool_t priExtendPrime2(
word p[], /*!< [out] расширенное простое число */
size_t l, /*!< [in] длина p в битах */
const word q[], /*!< [in] базовое простое число */
size_t n, /*!< [in] длина q в машинных словах */
const word a[], /*!< [in] делитель p - 1 */
size_t m, /*!< [in] длина m в машинных словах */
size_t trials, /*!< [in] число кандидатов */
size_t base_count, /*!< [in] число элементов факторной базы */
gen_i rng, /*!< [in] генератор случайных чисел */
void* rng_state, /*!< [in] состояние rng */
void* stack /*!< [in] вспомогательная память */
);
size_t priExtendPrime2_deep(size_t l, size_t n, size_t m, size_t base_count);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __BEE2_PRI_H */