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
/*
*******************************************************************************
\file bels.h
\brief STB 34.101.60 (bels): secret sharing algorithms
\project bee2 [cryptographic library]
\created 2013.05.14
\version 2023.02.02
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/
/*!
*******************************************************************************
\file bels.h
\brief Алгоритмы СТБ 34.101.60 (bels)
*******************************************************************************
*/
#ifndef __BEE2_BELS_H
#define __BEE2_BELS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bee2/defs.h"
/*!
*******************************************************************************
\file bels.h
Реализованы алгоритмы СТБ 34.101.60 (bels). При ссылках на алгоритмы
подразумеваются разделы СТБ 34.101.60-2013, в которых эти алгоритмы определены.
Алгоритмы предназначены для разделения секрета из len октетов,
где len = 16, 24 или 32. При разделении секрета используются открытые ключи mi,
которые также состоят из len октетов. Открытый ключ m0 является общим,
а остальные открытые ключи связаны с конкретными пользователями.
Число неприводимых многочленов:\n
l = 128, 256: (2^l - 2^{l/2}) / l;\n
l = 192: (2^192 - 2^96 - 2^64 + 2^27) / l.
Таким образом, случайный многочлен степени l окажется неприводимым
с вероятностью, близкой к 1/l.
Если проверить k * l случайных многочленов, то ни один из них не окажется
неприводимым с вероятностью, близкой к\n
p = (1 - 1/l)^{k * l} \approx e^{-k}.\n
В реализации\n
k = B_PER_IMPOSSIBLE * 3 / 4 > B_PER_IMPOSSIBLE * \log(2)\n
и поэтому p < 2^{-B_PER_IMPOSSIBLE}.
В функции belsGenM0() неуспех при k * l попытках генерации интерпретируется
как нарушение ожидаемых свойств ang с возвратом кода ошибки ERR_BAD_ANG.
Генерация открытых ключей пользователей основана на вспомогательном алгоритме
BuildIrred, описанном в 6.3. В этом алгоритме входной многочлен u
интерпретируется как элемент поля E = F_2[x]/(f0(x)),
где f0(x) = x^l + m0(x) -- неприводимый многочлен степени l.
Алгоритм BuildIrred возвращает минимальный многочлен f элемента u.
Многочлен f либо неприводим, либо f == 1. Если deg f = l,
то генерация завершена -- открытый ключ определяется по f.
Каждый неприводимый многочлен степени l является минимальным многочленом
для l различных элементов поля. Поэтому вероятность того, что f будет
иметь степень l близка к\n
(1 - 2^{-l/2}) [l = 128, 256]\n
(1 - 2^{-96} - ...) [l = 192].
В функциях belsGenMi(), belsGenMid() предпринимается\n
k = \max(3, B_PER_IMPOSSIBLE * 2 / l)\n
попытки генерации f. Ситуация, когда все попытки завершены с ошибкой,
считается невозможной и интерпретируется как неверные входные данные
(общему открытому ключу m0 соответствует многочлен f0,
который не является неприводимым) с возвратом кода ошибки ERR_BAD_PUBKEY.
\expect{ERR_BAD_INPUT} Все входные указатели действительны.
\safe todo
*******************************************************************************
*/
/*
*******************************************************************************
Открытые ключи
*******************************************************************************
*/
/*! \brief Загрузка стандартного открытого ключа
Загружается стандартный открытый ключ [len]m.
Загружается либо общий открытый ключ из таблицы A.1 (при num == 0),
либо открытый ключ пользователя номер num одной из таблиц A.2, A.3, A.4.
\expect{ERR_BAD_INPUT}
- len == 16 || len == 24 || len == 32;
- 0 <= num <= 16.
.
\return ERR_OK, если ключ успешно загружен, и код ошибки
в противном случае.
*/
err_t belsStdM(
octet m[], /*!< [out] открытый ключ */
size_t len, /*!< [in] длина ключа в октетах */
size_t num /*!< [in] номер ключа */
);
/*! \brief Проверка открытого ключа
Проверяется корректность открытого ключа [len]m.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\return ERR_OK, если ключ корректен, и код ошибки в противном случае.
*/
err_t belsValM(
const octet m[], /*!< [in] открытый ключ */
size_t len /*!< [in] длина ключа в октетах */
);
/*! \brief Генерация общего открытого ключа
Генерируется общий открытый ключ [len]m0. При генерации
используется генератор ang и его состояние ang_state.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\expect{ERR_BAD_ANG} Генератор ang выдает неповторяющиеся ключи-кандидаты.
\return ERR_OK, если ключ успешно сгенерирован, и код ошибки
в противном случае.
\remark Реализован алгоритм bels-genm0.
*/
err_t belsGenM0(
octet m0[], /*!< [out] общий открытый ключ */
size_t len, /*!< [in] длина ключа в октетах */
gen_i ang, /*!< [in] генератор произвольных чисел */
void* ang_state /*!< [in,out] состояние генератора */
);
/*! \brief Генерация открытых ключей пользователей
По общему открытому ключу [len]m0 октетов генерируется открытый ключ
[len]mi пользователя. При генерации используется генератор ang и его
состояние ang_state.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\expect{ERR_BAD_PUBKEY} Ключ m0 корректен.
\expect{ERR_BAD_ANG} Генератор ang корректен и выдает неповторяющиеся
ключи-кандидаты.
\return ERR_OK, если ключи успешно сгенерированы, и код ошибки
в противном случае.
\remark Частично реализован алгоритм bels-genmi. Для генерации набора
открытых ключей следует вызвать функцию несколько раз и проверить различие
полученных ключей.
*/
err_t belsGenMi(
octet mi[], /*!< [out] открытый ключ пользователя */
size_t len, /*!< [in] длина ключей в октетах */
const octet m0[], /*!< [in] общий открытый ключ */
gen_i ang, /*!< [in] генератор произвольных чисел */
void* ang_state /*!< [in,out] состояние генератора */
);
/*! \brief Генерация открытого ключа пользователя по идентификатору
По общему открытому ключу [len]m0 и идентификатору [id_len]id октетов
генерируется открытый ключ [len]mid пользователя с идентификатором
[id_len]id.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\expect{ERR_BAD_PUBKEY} Ключ m0 корректен.
\return ERR_OK, если ключ успешно сгенерирован, и код ошибки
в противном случае.
\remark Реализован алгоритм genmid.
*/
err_t belsGenMid(
octet mid[], /*!< [out] открытый ключ пользователя */
size_t len, /*!< [in] длина ключей в октетах */
const octet m0[], /*!< [in] общий открытый ключ */
const octet id[], /*!< [in] идентификатор */
size_t id_len /*!< [in] длина идентификаторa в октетах */
);
/*
*******************************************************************************
Разделение и восстановление секрета
*******************************************************************************
*/
/*! \brief Разделение секрета
Секрет [len]s разделяется с порогом threshold на count частичных секретов,
которые записываются в массив [count * len]si. При разделении используется
общий открытый ключ [len]m0 и открытые ключи пользователей из массива
[count * len]mi. Секреты и ключи размещаются в массивах si, mi
последовательными блоками из len октетов: первый блок соответствует
первому пользователю, второй -- второму и т.д. При разделении секрета
используется генератор rng и его состояние rng_state.
\expect{ERR_BAD_INPUT}
- len == 16 || len == 24 || len == 32;
- 0 < threshold <= count.
.
\expect{ERR_BAD_PUBKEY} Открытые ключи m0, mi корректны и отличаются
друг от друга.
\expect{ERR_BAD_RNG} Генератор rng (с состоянием rng_state) корректен.
\expect Генератор rng является криптографически стойким.
\return ERR_OK, если секрет успешно разделен, и код ошибки
в противном случае.
\remark Реализован алгоритм bels-share.
*/
err_t belsShare(
octet si[], /*!< [out] частичные секреты */
size_t count, /*!< [in] число пользователей */
size_t threshold, /*!< [in] пороговое число */
size_t len, /*!< [in] длина секрета в октетах */
const octet s[], /*!< [in] секрет */
const octet m0[], /*!< [in] общий открытый ключ */
const octet mi[], /*!< [in] открытые ключи пользователей */
gen_i rng, /*!< [in] генератор случайных чисел */
void* rng_state /*!< [in,out] состояние генератора */
);
/*! \brief Разделение секрета на стандартных открытых ключах
Секрет [len]s разделяется с порогом threshold на count частичных секретов,
которые записываются в массив [count * (len + 1)]si. При разделении
используются стандартные открытые ключи
belsStdM(m, len, i), i = 0, 1, ..., count.
Частичные секреты размещается в массиве si последовательными блоками из
len + 1 октетов: первый блок соответствует первому пользователю, второй --
второму и т.д. В первом октете блока указывается его номер (от 1 до count).
При разделении секрета используется генератор rng и его состояние
rng_state.
\expect{ERR_BAD_INPUT}
- len == 16 || len == 24 || len == 32;
- 0 < threshold <= count < = 16.
.
\expect{ERR_BAD_RNG} Генератор rng (с состоянием rng_state) корректен.
\expect Генератор rng является криптографически стойким.
\return ERR_OK, если секрет успешно разделен, и код ошибки в противном
случае.
\remark Реализован алгоритм bels-share.
*/
err_t belsShare2(
octet si[], /*!< [out] частичные секреты */
size_t count, /*!< [in] число пользователей */
size_t threshold, /*!< [in] пороговое число */
size_t len, /*!< [in] длина секрета в октетах */
const octet s[], /*!< [in] секрет */
gen_i rng, /*!< [in] генератор случайных чисел */
void* rng_state /*!< [in,out] состояние генератора */
);
/*! \brief Детерминированное разделение секрета на стандартных открытых ключах
Секрет [len]s разделяется с порогом threshold на count частичных секретов,
которые записываются в массив [count * (len + 1)]si. При разделении
используется стандартные открытые ключи
belsStdM(m, len, i), i = 0, 1, ..., count.
Секреты размещается в массиве si последовательными блоками из len + 1
октетов. В первом октете блока указывается его номер (от 1 до count).
Одноразовый ключ, который используется при разделении секрета, строится
по разделяемому ключу с помощью (экспериментального) детерминированного
алгоритма bels-genk.
\expect{ERR_BAD_INPUT}
- len == 16 || len == 24 || len == 32;
- 0 < threshold <= count <= 16.
.
\return ERR_OK, если секрет успешно разделен, и код ошибки в противном
случае.
\remark Реализован алгоритм bels-share.
\warning Экспериментальный режим.
*/
err_t belsShare3(
octet si[], /*!< [out] частичные секреты */
size_t count, /*!< [in] число пользователей */
size_t threshold, /*!< [in] пороговое число */
size_t len, /*!< [in] длина секрета в октетах */
const octet s[] /*!< [in] секрет */
);
/*! \brief Восстановление секрета
Секрет [len]s восстанавливается по count частичным секретам из массива
[count * len]si. При восстановлении используется общий открытый ключ
[len]m0 и открытые ключи пользователей из массива [count * len]mi.
Частичные секреты и открытые ключи размещаются в массивах si, mi
последовательными блоками из len октетов.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\expect{ERR_BAD_PUBKEY} Открытые ключи m0, mi корректны и отличаются
друг от друга.
\return ERR_OK, если секрет успешно восстановлен, и код ошибки в противном
случае.
\remark Реализован алгоритм bels-recover. Успешное восстановление не
означает, что секрет будет совпадать с первоначально разделенным. Этого,
например, не произойдет, если число частичных секретов меньше порога,
использованого при разделении.
*/
err_t belsRecover(
octet s[], /*!< [out] восстановленный секрет */
size_t count, /*!< [in] число пользователей */
size_t len, /*!< [in] длина секретов в октетах */
const octet si[], /*!< [in] частичные секреты */
const octet m0[], /*!< [in] общий открытый ключ */
const octet mi[] /*!< [in] открытые ключи пользователей */
);
/*! \brief Восстановление секрета на стандартных открытых ключах
Секрет [len]s восстанавливается по count частичным секретам из массива
[count * len]si. При восстановлении используется стандартные открытые
ключи belsStdM(m, len, i). Частичные секреты размещаются в массиве si
последовательными блоками из len + 1 октетов. Первый октет блока задает
номер открытого ключа.
\expect{ERR_BAD_INPUT} len == 16 || len == 24 || len == 32.
\expect{ERR_BAD_PUBKEY} Номера открытых ключей, указанные в первых октетах
частичных секретов, принадлежат интервалу {1, 2, ..., 16} и отличаются
друг от друга.
\return ERR_OK, если секрет успешно восстановлен, и код ошибки в противном
случае.
\remark Реализован алгоритм bels-recover. Успешное восстановление не
означает, что секрет будет совпадать с первоначально разделенным. Этого,
например, не произойдет, если число частичных секретов меньше порога,
использованого при разделении.
*/
err_t belsRecover2(
octet s[], /*!< [out] восстановленный секрет */
size_t count, /*!< [in] число пользователей */
size_t len, /*!< [in] длина секретов в октетах */
const octet si[] /*!< [in] частичные секреты */
);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __BEE2_BELS_H */