agievich / bee2
1
/*
2
*******************************************************************************
3
\file bign.c
4
\brief STB 34.101.45 (bign): digital signature and key transport algorithms
5
\project bee2 [cryptographic library]
6
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
7
\created 2012.04.27
8
\version 2018.07.04
9
\license This program is released under the GNU General Public License 
10
version 3. See Copyright Notices in bee2/info.h.
11
*******************************************************************************
12
*/
13

14
#include "bee2/core/blob.h"
15
#include "bee2/core/err.h"
16
#include "bee2/core/der.h"
17
#include "bee2/core/mem.h"
18
#include "bee2/core/oid.h"
19
#include "bee2/core/str.h"
20
#include "bee2/core/util.h"
21
#include "bee2/crypto/belt.h"
22
#include "bee2/crypto/bign.h"
23
#include "crypto/bign_lcl.h"
24
#include "bee2/math/gfp.h"
25
#include "bee2/math/ecp.h"
26
#include "bee2/math/pri.h"
27
#include "bee2/math/ww.h"
28
#include "bee2/math/zz.h"
29

30
/*
31
*******************************************************************************
32
Стандартные параметры: приложение Б к СТБ 34.101.45
33
*******************************************************************************
34
*/
35

36
// bign-curve128v1
37
static const char _curve128v1_name[] = "1.2.112.0.2.0.34.101.45.3.1";
38

39
static const octet _curve128v1_p[32] = {
40
	0x43, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
41
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
42
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
43
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
44
};
45

46
static const octet _curve128v1_a[32] = {
47
	0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
49
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
50
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
51
};
52

53
static const octet _curve128v1_b[32] = {
54
	0xF1, 0x03, 0x9C, 0xD6, 0x6B, 0x7D, 0x2E, 0xB2,
55
	0x53, 0x92, 0x8B, 0x97, 0x69, 0x50, 0xF5, 0x4C,
56
	0xBE, 0xFB, 0xD8, 0xE4, 0xAB, 0x3A, 0xC1, 0xD2,
57
	0xED, 0xA8, 0xF3, 0x15, 0x15, 0x6C, 0xCE, 0x77,
58
};
59

60
static const octet _curve128v1_seed[8] = {
61
	0x5E, 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
62
};
63

64
static const octet _curve128v1_q[32] = {
65
	0x07, 0x66, 0x3D, 0x26, 0x99, 0xBF, 0x5A, 0x7E,
66
	0xFC, 0x4D, 0xFB, 0x0D, 0xD6, 0x8E, 0x5C, 0xD9,
67
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
68
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
69
};
70

71
static const octet _curve128v1_yG[32] = {
72
	0x93, 0x6A, 0x51, 0x04, 0x18, 0xCF, 0x29, 0x1E,
73
	0x52, 0xF6, 0x08, 0xC4, 0x66, 0x39, 0x91, 0x78,
74
	0x5D, 0x83, 0xD6, 0x51, 0xA3, 0xC9, 0xE4, 0x5C,
75
	0x9F, 0xD6, 0x16, 0xFB, 0x3C, 0xFC, 0xF7, 0x6B,
76
};
77

78
// bign-curve192v1
79
static const char _curve192v1_name[] = "1.2.112.0.2.0.34.101.45.3.2";
80

81
static const octet _curve192v1_p[48] = {
82
	0xC3, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
83
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
84
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
85
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
86
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
87
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
88
};
89

90
static const octet _curve192v1_a[48] = {
91
	0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
92
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
93
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
94
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
95
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
97
};
98

99
static const octet _curve192v1_b[48] = {
100
	0x64, 0xBF, 0x73, 0x68, 0x23, 0xFC, 0xA7, 0xBC,
101
	0x7C, 0xBD, 0xCE, 0xF3, 0xF0, 0xE2, 0xBD, 0x14,
102
	0x3A, 0x2E, 0x71, 0xE9, 0xF9, 0x6A, 0x21, 0xA6,
103
	0x96, 0xB1, 0xFB, 0x0F, 0xBB, 0x48, 0x27, 0x71,
104
	0xD2, 0x34, 0x5D, 0x65, 0xAB, 0x5A, 0x07, 0x33,
105
	0x20, 0xEF, 0x9C, 0x95, 0xE1, 0xDF, 0x75, 0x3C,
106
};
107

108
static const octet _curve192v1_seed[8] = {
109
	0x23, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110
};
111

112
static const octet _curve192v1_q[48] = {
113
	0xB7, 0xA7, 0x0C, 0xF3, 0x3F, 0xDC, 0xB7, 0x3D,
114
	0x0A, 0xFF, 0xA4, 0xA6, 0xE7, 0xDA, 0x46, 0x80,
115
	0xBB, 0x7B, 0xAF, 0x73, 0x03, 0xC4, 0xCC, 0x6C,
116
	0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
117
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
118
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
119
};
120

121
static const octet _curve192v1_yG[48] =
122
{
123
	0x51, 0xC4, 0x33, 0xF7, 0x31, 0xCB, 0x5E, 0xEA,
124
	0xF9, 0x42, 0x2A, 0x6B, 0x27, 0x3E, 0x40, 0x84,
125
	0x55, 0xD3, 0xB1, 0x66, 0x9E, 0xE7, 0x49, 0x05,
126
	0xA0, 0xFF, 0x86, 0xDC, 0x11, 0x9A, 0x72, 0x3A,
127
	0x89, 0xBF, 0x2D, 0x43, 0x7E, 0x11, 0x30, 0x63,
128
	0x9E, 0x9E, 0x2E, 0xA8, 0x24, 0x82, 0x43, 0x5D,
129
};
130

131
// bign-curve256v1
132
static const char _curve256v1_name[] = "1.2.112.0.2.0.34.101.45.3.3";
133

134
static const octet _curve256v1_p[64] = {
135
	0xC7, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
136
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
137
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
138
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
139
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
140
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
141
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
142
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
143
};
144

145
static const octet _curve256v1_a[64] = {
146
	0xC4, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
147
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
148
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
149
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
150
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
151
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
152
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
153
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
154
};
155

156
static const octet _curve256v1_b[64] = {
157
	0x90, 0x9C, 0x13, 0xD6, 0x98, 0x69, 0x34, 0x09,
158
	0x7A, 0xA2, 0x49, 0x3A, 0x27, 0x22, 0x86, 0xEA,
159
	0x43, 0xA2, 0xAC, 0x87, 0x8C, 0x00, 0x33, 0x29,
160
	0x95, 0x5E, 0x24, 0xC4, 0xB5, 0xDC, 0x11, 0x27,
161
	0x88, 0xB0, 0xAD, 0xDA, 0xE3, 0x13, 0xCE, 0x17,
162
	0x51, 0x25, 0x5D, 0xDD, 0xEE, 0xA9, 0xC6, 0x5B,
163
	0x89, 0x58, 0xFD, 0x60, 0x6A, 0x5D, 0x8C, 0xD8,
164
	0x43, 0x8C, 0x3B, 0x93, 0x44, 0x59, 0xB4, 0x6C,
165
};
166

167
static const octet _curve256v1_seed[8] = {
168
	0xAE, 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
169
};
170

171
static const octet _curve256v1_q[64] = {
172
	0xF1, 0x8E, 0x06, 0x0D, 0x49, 0xAD, 0xFF, 0xDC,
173
	0x32, 0xDF, 0x56, 0x95, 0xE5, 0xCA, 0x1B, 0x36,
174
	0xF4, 0x13, 0x21, 0x2E, 0xB0, 0xEB, 0x6B, 0xF2,
175
	0x4E, 0x00, 0x98, 0x01, 0x2C, 0x09, 0xC0, 0xB2,
176
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
177
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
178
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
179
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
180
};
181

182
static const octet _curve256v1_yG[64] =
183
{
184
	0xBD, 0xED, 0xEF, 0xCE, 0x6F, 0xAE, 0x92, 0xB7,
185
	0x04, 0x0D, 0x4C, 0xC9, 0xB9, 0x83, 0xAA, 0x67,
186
	0x61, 0x22, 0xE8, 0xEE, 0x95, 0x73, 0x77, 0xFF,
187
	0xD2, 0x6F, 0xFA, 0x0E, 0xE2, 0xDD, 0x73, 0x69,
188
	0xDA, 0xCA, 0xCC, 0x00, 0x1B, 0xF8, 0xED, 0xD2,
189
	0xE2, 0xBC, 0x61, 0xB3, 0xB3, 0x41, 0xAB, 0xB0,
190
	0xAB, 0x8F, 0xD1, 0xA0, 0xF7, 0xE6, 0x82, 0xB1,
191
	0x81, 0x76, 0x03, 0xE4, 0x7A, 0xFF, 0x26, 0xA8,
192
};
193

194
/*
195
*******************************************************************************
196
Загрузка стандартных параметров
197
*******************************************************************************
198
*/
199

200 1
err_t bignStdParams(bign_params* params, const char* name)
201
{
202 1
	if (!memIsValid(params, sizeof(bign_params)))
203 0
		return ERR_BAD_INPUT;
204 1
	if (strEq(name, _curve128v1_name))
205
	{
206 1
		params->l = 128;
207 1
		memCopy(params->p, _curve128v1_p, 32);
208 1
		memCopy(params->a, _curve128v1_a, 32);
209 1
		memCopy(params->seed, _curve128v1_seed, 8);
210 1
		memCopy(params->b, _curve128v1_b, 32);
211 1
		memCopy(params->q, _curve128v1_q, 32);
212 1
		memCopy(params->yG, _curve128v1_yG, 32);
213 1
		return ERR_OK;
214
	}
215 1
	if (strEq(name, _curve192v1_name))
216
	{
217 1
		params->l = 192;
218 1
		memCopy(params->p, _curve192v1_p, 48);
219 1
		memCopy(params->a, _curve192v1_a, 48);
220 1
		memCopy(params->seed, _curve192v1_seed, 8);
221 1
		memCopy(params->b, _curve192v1_b, 48);
222 1
		memCopy(params->q, _curve192v1_q, 48);
223 1
		memCopy(params->yG, _curve192v1_yG, 48);
224 1
		return ERR_OK;
225
	}
226 1
	if (strEq(name, _curve256v1_name))
227
	{
228 1
		params->l = 256;
229 1
		memCopy(params->p, _curve256v1_p, 64);
230 1
		memCopy(params->a, _curve256v1_a, 64);
231 1
		memCopy(params->seed, _curve256v1_seed, 8);
232 1
		memCopy(params->b, _curve256v1_b, 64);
233 1
		memCopy(params->q, _curve256v1_q, 64);
234 1
		memCopy(params->yG, _curve256v1_yG, 64);
235 1
		return ERR_OK;
236
	}
237 0
	return ERR_FILE_NOT_FOUND;
238
}
239

240
/*
241
*******************************************************************************
242
Создание / закрытие эллиптической кривой
243
*******************************************************************************
244
*/
245

246 1
err_t bignStart(void* state, const bign_params* params)
247
{
248
	// размерности
249
	size_t no, n;
250
	size_t f_keep;
251
	size_t ec_keep;
252
	// состояние
253
	qr_o* f;		/* поле */
254
	ec_o* ec;		/* кривая */
255
	void* stack;	/* вложенный стек */
256
	// pre
257 1
	ASSERT(memIsValid(params, sizeof(bign_params)));
258 1
	ASSERT(params->l == 128 || params->l == 192  || params->l == 256);
259 1
	ASSERT(memIsValid(state, bignStart_keep(params->l, 0)));
260
	// определить размерности
261 1
	no = O_OF_B(2 * params->l);
262 1
	n = W_OF_B(2 * params->l);
263 1
	f_keep = gfpCreate_keep(no);
264 1
	ec_keep = ecpCreateJ_keep(n);
265
	// создать поле и выполнить минимальные проверки p
266 1
	f = (qr_o*)((octet*)state + ec_keep);
267 1
	stack = (octet*)f + f_keep;
268 1
	if (!gfpCreate(f, params->p, no, stack) ||
269 1
		wwBitSize(f->mod, n) != params->l * 2 ||
270 1
		wwGetBits(f->mod, 0, 2) != 3)
271 0
		return ERR_BAD_PARAMS;
272
	// создать кривую и группу, выполнить минимальную проверку order
273 1
	ec = (ec_o*)state;
274 1
	if (!ecpCreateJ(ec, f, params->a, params->b, stack) ||
275 1
		!ecCreateGroup(ec, 0, params->yG, params->q, no, 1, stack) ||
276 1
		wwBitSize(ec->order, n) != params->l * 2 ||
277 1
		zzIsEven(ec->order, n))
278 0
		return ERR_BAD_PARAMS;
279
	// присоединить f к ec
280 1
	objAppend(ec, f, 0);
281
	// все нормально
282 1
	return ERR_OK;
283
}
284

285 1
size_t bignStart_keep(size_t l, bign_deep_i deep)
286
{
287
	// размерности
288 1
	size_t no = O_OF_B(2 * l);
289 1
	size_t n = W_OF_B(2 * l);
290 1
	size_t f_keep = gfpCreate_keep(no);
291 1
	size_t f_deep = gfpCreate_deep(no);
292 1
	size_t ec_d = 3;
293 1
	size_t ec_keep = ecpCreateJ_keep(n);
294 1
	size_t ec_deep = ecpCreateJ_deep(n, f_deep);
295
	// расчет
296 1
	return f_keep + ec_keep +
297 1
		utilMax(3,
298
			ec_deep,
299
			ecCreateGroup_deep(f_deep),
300
			deep ? deep(n, f_deep, ec_d, ec_deep) : 0);
301
}
302

303
/*
304
*******************************************************************************
305
Проверка параметров
306

307
-#	l \in {128, 192, 256} (bignCreateEc)
308
-#	2^{l - 1} < p, q < 2^l (bignCreateEc)
309
-#	p -- простое (ecpIsValid)
310
-#	q -- простое (ecpIsSafeGroup)
311
-#	p \equiv 3 \mod 4 (bignCreateEc)
312
-#	q != p (ecpIsSafeGroup)
313
-#	p^m \not\equiv 1 (mod q), m = 1, 2,..., 50 (ecpIsSafeGroup)
314
-#	a, b < p (ecpCreateJ in bignCreateEc)
315
-#	0 != b (bignValParams)
316
-#	b \equiv B (mod p) (bignValParams)
317
-#	4a^3 + 27b^2 \not\equiv 0 (\mod p) (ecpIsValid)
318
-#	(b / p) = 1 (zzJacobi)
319
-#	G = (0, b^{(p + 1) /4}) (bignValParams)
320
-#	qG = O (ecpHasOrder)
321
*******************************************************************************
322
*/
323

324 1
static size_t bignValParams_deep(size_t n, size_t f_deep, size_t ec_d,
325
	size_t ec_deep)
326
{
327 1
	return beltHash_keep() + O_OF_B(512) +
328 1
		utilMax(6,
329
			beltHash_keep(),
330
			ecpIsValid_deep(n, f_deep),
331
			ecpIsSafeGroup_deep(n),
332
			ecpIsOnA_deep(n, f_deep),
333
			qrPower_deep(n, n, f_deep),
334
			ecHasOrderA_deep(n, ec_d, ec_deep, n));
335
}
336

337 1
err_t bignValParams(const bign_params* params)
338
{
339
	err_t code;
340
	size_t no, n;
341
	// состояние (буферы могут пересекаться)
342
	void* state;
343
	ec_o* ec;				/* описание эллиптической кривой */
344
	octet* hash_state;		/* [beltHash_keep] состояние хэширования */
345
	octet* hash_data;		/* [8] данные хэширования */
346
	word* B;				/* [W_OF_B(512)] переменная B */
347
	octet* stack;
348
	// проверить params
349 1
	if (!memIsValid(params, sizeof(bign_params)))
350 0
		return ERR_BAD_INPUT;
351 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
352 0
		return ERR_BAD_PARAMS;
353
	// создать состояние
354 1
	state = blobCreate(bignStart_keep(params->l, bignValParams_deep));
355 1
	if (state == 0)
356 0
		return ERR_OUTOFMEMORY;
357
	// старт
358 1
	code = bignStart(state, params);
359 1
	ERR_CALL_HANDLE(code, blobClose(state));
360 1
	ec = (ec_o*)state;
361
	// размерности
362 1
	no  = ec->f->no;
363 1
	n = ec->f->n;
364
	// раскладка состояния
365 1
	hash_state = objEnd(ec, octet);
366 1
	hash_data = hash_state + beltHash_keep();
367 1
	B = (word*)hash_data;
368 1
	stack = hash_data + O_OF_B(512);
369
	// belt-hash(p..)
370 1
	beltHashStart(hash_state);
371 1
	beltHashStepH(params->p, no, hash_state);
372
	// belt-hash(..a..)
373 1
	beltHashStepH(params->a, no, hash_state);
374 1
	memCopy(stack, hash_state, beltHash_keep());
375
	// belt-hash(..seed)
376 1
	memCopy(hash_data, params->seed, 8);
377 1
	beltHashStepH(hash_data, 8, hash_state);
378
	// belt-hash(..seed + 1)
379 1
	wwFrom(B, hash_data, 8);
380 1
	zzAddW2(B, W_OF_O(8), 1);
381 1
	wwTo(hash_data, 8, B);
382 1
	beltHashStepH(hash_data, 8, stack);
383
	// B <- belt-hash(p || a || seed) || belt-hash(p || a || seed + 1)
384 1
	beltHashStepG(hash_data, hash_state);
385 1
	beltHashStepG(hash_data + 32, stack);
386 1
	wwFrom(B, hash_data, 64);
387
	// B <- B \mod p
388 1
	zzMod(B, B, W_OF_O(64), ec->f->mod, n, stack);
389 1
	wwTo(B, 64, B);
390
	// проверить условия алгоритма 6.1.4
391 1
	if (qrFrom(B, (octet*)B, ec->f, stack) &&
392 1
		wwEq(B, ec->B, n) &&
393 1
		!wwIsZero(ec->B, n) &&
394 1
		ecpIsValid(ec, stack) &&
395 1
		ecpIsSafeGroup(ec, 50, stack) &&
396 1
		zzJacobi(ec->B, n, ec->f->mod, n, stack) == 1)
397
	{
398
		// B <- b^{(p + 1) / 4} = \sqrt{b} mod p
399 1
		wwCopy(B, ec->f->mod, n);
400 1
		zzAddW2(B, n, 1);
401 1
		wwShLo(B, n, 2);
402 1
		qrPower(B, ec->B, B, n, ec->f, stack);
403
		// оставшиеся условия
404 1
		if (!wwEq(B, ecY(ec->base, n), n) ||
405 1
			!ecHasOrderA(ec->base, ec, ec->order, n, stack))
406 0
			code = ERR_BAD_PARAMS;
407
	}
408
	else
409 0
		code = ERR_BAD_PARAMS;
410
	// завершение
411 1
	blobClose(state);
412 1
	return code;
413
}
414

415
/*
416
*******************************************************************************
417
Идентификатор объекта
418
*******************************************************************************
419
*/
420

421 1
err_t bignOidToDER(octet oid_der[], size_t* oid_len, const char* oid)
422
{
423
	size_t len;
424 1
	if (!strIsValid(oid) || 
425 1
		!memIsValid(oid_len, sizeof(size_t)) ||
426 1
		!memIsNullOrValid(oid_der, *oid_len))
427 0
		return ERR_BAD_INPUT;
428 1
	len = oidToDER(0, oid);
429 1
	if (len == SIZE_MAX)
430 0
		return ERR_BAD_OID;
431 1
	if (oid_der)
432
	{
433 1
		if (*oid_len < len)
434 0
			return ERR_OUTOFMEMORY;
435 1
		oidToDER(oid_der, oid);
436
	}
437 1
	*oid_len = len;
438 1
	return ERR_OK;
439
}
440

441
/*
442
*******************************************************************************
443
Управление ключами
444
*******************************************************************************
445
*/
446

447 1
static size_t bignGenKeypair_deep(size_t n, size_t f_deep, size_t ec_d,
448
	size_t ec_deep)
449
{
450 1
	return O_OF_W(n + 2 * n) +
451 1
		ecMulA_deep(n, ec_d, ec_deep, n);
452
}
453

454 1
err_t bignGenKeypair(octet privkey[], octet pubkey[],
455
	const bign_params* params, gen_i rng, void* rng_state)
456
{
457
	err_t code;
458
	size_t no, n;
459
	// состояние
460
	void* state;
461
	ec_o* ec;				/* описание эллиптической кривой */
462
	word* d;				/* [n] личный ключ */
463
	word* Q;				/* [2n] открытый ключ */
464
	void* stack;
465
	// проверить params
466 1
	if (!memIsValid(params, sizeof(bign_params)))
467 0
		return ERR_BAD_INPUT;
468 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
469 0
		return ERR_BAD_PARAMS;
470
	// проверить rng
471 1
	if (rng == 0)
472 0
		return ERR_BAD_RNG;
473
	// создать состояние
474 1
	state = blobCreate(bignStart_keep(params->l, bignGenKeypair_deep));
475 1
	if (state == 0)
476 0
		return ERR_OUTOFMEMORY;
477
	// старт
478 1
	code = bignStart(state, params);
479 1
	ERR_CALL_HANDLE(code, blobClose(state));
480 1
	ec = (ec_o*)state;
481
	// размерности
482 1
	no  = ec->f->no;
483 1
	n = ec->f->n;
484
	// проверить входные указатели
485 1
	if (!memIsValid(privkey, no) ||
486 1
		!memIsValid(pubkey, 2 * no))
487
	{
488 0
		blobClose(state);
489 0
		return ERR_BAD_INPUT;
490
	}
491
	// раскладка состояния
492 1
	d = objEnd(ec, word);
493 1
	Q = d + n;
494 1
	stack = Q + 2 * n;
495
	// d <-R {1,2,..., q - 1}
496 1
	if (!zzRandNZMod(d, ec->f->mod, n, rng, rng_state))
497
	{
498 0
		blobClose(state);
499 0
		return ERR_BAD_RNG;
500
	}
501
	// Q <- d G
502 1
	if (ecMulA(Q, ec->base, ec, d, n, stack))
503
	{
504
		// выгрузить ключи
505 1
		wwTo(privkey, no, d);
506 1
		qrTo(pubkey, ecX(Q), ec->f, stack);
507 1
		qrTo(pubkey + ec->f->no, ecY(Q, n), ec->f, stack);
508
	}
509
	else
510 0
		code = ERR_BAD_PARAMS;
511
	// завершение
512 1
	blobClose(state);
513 1
	return code;
514
}
515

516 1
static size_t bignValPubkey_deep(size_t n, size_t f_deep, size_t ec_d,
517
	size_t ec_deep)
518
{
519 1
	return O_OF_W(2 * n) +
520 1
		ecpIsOnA_deep(n, f_deep);
521
}
522

523 1
err_t bignValPubkey(const bign_params* params, const octet pubkey[])
524
{
525
	err_t code;
526
	size_t no, n;
527
	// состояние
528
	void* state;
529
	ec_o* ec;			/* описание эллиптической кривой */
530
	word* Q;			/* [2n] открытый ключ */
531
	void* stack;
532
	// проверить params
533 1
	if (!memIsValid(params, sizeof(bign_params)))
534 0
		return ERR_BAD_INPUT;
535 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
536 0
		return ERR_BAD_PARAMS;
537
	// создать состояние
538 1
	state = blobCreate(bignStart_keep(params->l, bignValPubkey_deep));
539 1
	if (state == 0)
540 0
		return ERR_OUTOFMEMORY;
541
	// старт
542 1
	code = bignStart(state, params);
543 1
	ERR_CALL_HANDLE(code, blobClose(state));
544 1
	ec = (ec_o*)state;
545
	// размерности
546 1
	no  = ec->f->no;
547 1
	n = ec->f->n;
548
	// проверить входные указатели
549 1
	if (!memIsValid(pubkey, 2 * no))
550
	{
551 0
		blobClose(state);
552 0
		return ERR_BAD_INPUT;
553
	}
554
	// раскладка состояния
555 1
	Q = objEnd(ec, word);
556 1
	stack = Q + 2 * n;
557
	// загрузить pt
558 1
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
559 1
		!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack))
560
	{
561 0
		blobClose(state);
562 0
		return ERR_BAD_PUBKEY;
563
	}
564
	// Q \in ec?
565 1
	code = ecpIsOnA(Q, ec, stack) ? ERR_OK : ERR_BAD_PUBKEY;
566
	// завершение
567 1
	blobClose(state);
568 1
	return code;
569
}
570

571 1
static size_t bignCalcPubkey_deep(size_t n, size_t f_deep, size_t ec_d,
572
	size_t ec_deep)
573
{
574 1
	return O_OF_W(n + 2 * n) +
575 1
		ecMulA_deep(n, ec_d, ec_deep, n);
576
}
577

578 1
err_t bignCalcPubkey(octet pubkey[], const bign_params* params,
579
	const octet privkey[])
580
{
581
	err_t code;
582
	size_t no, n;
583
	// состояние
584
	void* state;
585
	ec_o* ec;				/* описание эллиптической кривой */
586
	word* d;				/* [n] личный ключ */
587
	word* Q;				/* [2n] открытый ключ */
588
	void* stack;
589
	// проверить params
590 1
	if (!memIsValid(params, sizeof(bign_params)))
591 0
		return ERR_BAD_INPUT;
592 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
593 0
		return ERR_BAD_PARAMS;
594
	// создать состояние
595 1
	state = blobCreate(bignStart_keep(params->l, bignCalcPubkey_deep));
596 1
	if (state == 0)
597 0
		return ERR_OUTOFMEMORY;
598
	// старт
599 1
	code = bignStart(state, params);
600 1
	ERR_CALL_HANDLE(code, blobClose(state));
601 1
	ec = (ec_o*)state;
602
	// размерности
603 1
	no  = ec->f->no;
604 1
	n = ec->f->n;
605
	// проверить входные указатели
606 1
	if (!memIsValid(privkey, no) ||
607 1
		!memIsValid(pubkey, 2 * no))
608
	{
609 0
		blobClose(state);
610 0
		return ERR_BAD_INPUT;
611
	}
612
	// раскладка состояния
613 1
	d = objEnd(ec, word);
614 1
	Q = d + n;
615 1
	stack = Q + 2 * n;
616
	// загрузить d
617 1
	wwFrom(d, privkey, no);
618 1
	if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
619
	{
620 0
		blobClose(state);
621 0
		return ERR_BAD_PRIVKEY;
622
	}
623
	// Q <- d G
624 1
	if (ecMulA(Q, ec->base, ec, d, n, stack))
625
	{
626
		// выгрузить открытый ключ
627 1
		qrTo(pubkey, ecX(Q), ec->f, stack);
628 1
		qrTo(pubkey + no, ecY(Q, n), ec->f, stack);
629
	}
630
	else
631 0
		code = ERR_BAD_PARAMS;
632
	// завершение
633 1
	blobClose(state);
634 1
	return code;
635
}
636

637 1
static size_t bignDH_deep(size_t n, size_t f_deep, size_t ec_d,
638
	size_t ec_deep)
639
{
640 1
	return O_OF_W(n + 2 * n) +
641 1
		utilMax(2,
642
			ecpIsOnA_deep(n, f_deep),
643
			ecMulA_deep(n, ec_d, ec_deep, n));
644
}
645

646 1
err_t bignDH(octet key[], const bign_params* params, const octet privkey[],
647
	const octet pubkey[], size_t key_len)
648
{
649
	err_t code;
650
	size_t no, n;
651
	// состояние
652
	void* state;
653
	ec_o* ec;				/* описание эллиптической кривой */
654
	word* d;				/* [n] личный ключ */
655
	word* Q;				/* [2n] открытый ключ */
656
	void* stack;
657
	// проверить params
658 1
	if (!memIsValid(params, sizeof(bign_params)))
659 0
		return ERR_BAD_INPUT;
660 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
661 0
		return ERR_BAD_PARAMS;
662
	// создать состояние
663 1
	state = blobCreate(bignStart_keep(params->l, bignDH_deep));
664 1
	if (state == 0)
665 0
		return ERR_OUTOFMEMORY;
666
	// старт
667 1
	code = bignStart(state, params);
668 1
	ERR_CALL_HANDLE(code, blobClose(state));
669 1
	ec = (ec_o*)state;
670
	// размерности
671 1
	no  = ec->f->no;
672 1
	n = ec->f->n;
673
	// проверить длину key
674 1
	if (key_len > 2 * no)
675
	{
676 0
		blobClose(state);
677 0
		return ERR_BAD_SHAREKEY;
678
	}
679
	// проверить входные указатели
680 1
	if (!memIsValid(privkey, no) ||
681 1
		!memIsValid(pubkey, 2 * no) ||
682 1
		!memIsValid(key, key_len))
683
	{
684 0
		blobClose(state);
685 0
		return ERR_BAD_INPUT;
686
	}
687
	// раскладка состояния
688 1
	d = objEnd(ec, word);
689 1
	Q = d + n;
690 1
	stack = Q + 2 * n;
691
	// загрузить d
692 1
	wwFrom(d, privkey, no);
693 1
	if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
694
	{
695 0
		blobClose(state);
696 0
		return ERR_BAD_PRIVKEY;
697
	}
698
	// загрузить Q
699 1
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
700 1
		!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack) ||
701 1
		!ecpIsOnA(Q, ec, stack))
702
	{
703 0
		blobClose(state);
704 0
		return ERR_BAD_PUBKEY;
705
	}
706
	// Q <- d Q
707 1
	if (ecMulA(Q, Q, ec, d, n, stack))
708
	{
709
		// выгрузить общий ключ
710 1
		qrTo((octet*)Q, ecX(Q), ec->f, stack);
711 1
		if (key_len > no)
712 1
			qrTo((octet*)Q + no, ecY(Q, n), ec->f, stack);
713 1
		memCopy(key, Q, key_len);
714
	}
715
	else
716 0
		code = ERR_BAD_PARAMS;
717
	// завершение
718 1
	blobClose(state);
719 1
	return code;
720
}
721

722
/*
723
*******************************************************************************
724
Выработка ЭЦП
725
*******************************************************************************
726
*/
727

728 1
static size_t bignSign_deep(size_t n, size_t f_deep, size_t ec_d,
729
	size_t ec_deep)
730
{
731 1
	return O_OF_W(4 * n) +
732 1
		utilMax(4,
733
			beltHash_keep(),
734
			ecMulA_deep(n, ec_d, ec_deep, n),
735
			zzMul_deep(n / 2, n),
736 1
			zzMod_deep(n + n / 2 + 1, n));
737
}
738

739 1
err_t bignSign(octet sig[], const bign_params* params, const octet oid_der[],
740
	size_t oid_len, const octet hash[], const octet privkey[], gen_i rng, 
741
	void* rng_state)
742
{
743
	err_t code;
744
	size_t no, n;
745
	// состояние (буферы могут пересекаться)
746
	void* state;			
747
	ec_o* ec;				/* описание эллиптической кривой */
748
	word* d;				/* [n] личный ключ */
749
	word* k;				/* [n] одноразовый личный ключ */
750
	word* R;				/* [2n] точка R */
751
	word* s0;				/* [n/2] первая часть подписи */
752
	word* s1;				/* [n] вторая часть подписи */
753
	octet* stack;
754
	// проверить params
755 1
	if (!memIsValid(params, sizeof(bign_params)))
756 0
		return ERR_BAD_INPUT;
757 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
758 0
		return ERR_BAD_PARAMS;
759
	// проверить oid_der
760 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
761 0
		return ERR_BAD_OID;
762
	// проверить rng
763 1
	if (rng == 0)
764 0
		return ERR_BAD_RNG;
765
	// создать состояние
766 1
	state = blobCreate(bignStart_keep(params->l, bignSign_deep));
767 1
	if (state == 0)
768 0
		return ERR_OUTOFMEMORY;
769
	// старт
770 1
	code = bignStart(state, params);
771 1
	ERR_CALL_HANDLE(code, blobClose(state));
772 1
	ec = (ec_o*)state;
773
	// размерности
774 1
	no  = ec->f->no;
775 1
	n = ec->f->n;
776
	// проверить входные указатели
777 1
	if (!memIsValid(hash, no) ||
778 1
		!memIsValid(privkey, no) ||
779 1
		!memIsValid(sig, no + no / 2))
780
	{
781 0
		blobClose(state);
782 0
		return ERR_BAD_INPUT;
783
	}
784
	// раскладка состояния
785 1
	d = s1 = objEnd(ec, word);
786 1
	k = d + n;
787 1
	R = k + n;
788 1
	s0 = R + n + n / 2;
789 1
	stack = (octet*)(R + 2 * n);
790
	// загрузить d
791 1
	wwFrom(d, privkey, no);
792 1
	if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
793
	{
794 0
		blobClose(state);
795 0
		return ERR_BAD_PRIVKEY;
796
	}
797
	// сгенерировать k с помощью rng
798 1
	if (!zzRandNZMod(k, ec->order, n, rng, rng_state))
799
	{
800 0
		blobClose(state);
801 0
		return ERR_BAD_RNG;
802
	}
803
	// R <- k G
804 1
	if (!ecMulA(R, ec->base, ec, k, n, stack))
805
	{
806 0
		blobClose(state);
807 0
		return ERR_BAD_PARAMS;
808
	}
809 1
	qrTo((octet*)R, ecX(R), ec->f, stack);
810
	// s0 <- belt-hash(oid || R || H)
811 1
	beltHashStart(stack);
812 1
	beltHashStepH(oid_der, oid_len, stack);
813 1
	beltHashStepH(R, no, stack);
814 1
	beltHashStepH(hash, no, stack);
815 1
	beltHashStepG2(sig, no / 2, stack);
816 1
	wwFrom(s0, sig, no / 2);
817
	// R <- (s0 + 2^l) d
818 1
	zzMul(R, s0, n / 2, d, n, stack);
819 1
	R[n + n / 2] = zzAdd(R + n / 2, R + n / 2, d, n);
820
	// s1 <- R mod q
821 1
	zzMod(s1, R, n + n / 2 + 1, ec->order, n, stack);
822
	// s1 <- (k - s1 - H) mod q
823 1
	zzSubMod(s1, k, s1, ec->order, n);
824 1
	wwFrom(k, hash, no);
825 1
	zzSubMod(s1, s1, k, ec->order, n);
826
	// выгрузить s1
827 1
	wwTo(sig + no / 2, no, s1);
828
	// все нормально
829 1
	blobClose(state);
830 1
	return ERR_OK;
831
}
832

833 1
static size_t bignSign2_deep(size_t n, size_t f_deep, size_t ec_d,
834
	size_t ec_deep)
835
{
836 1
	return O_OF_W(4 * n) + beltHash_keep() +
837 1
		utilMax(5,
838
			beltHash_keep(),
839
			beltKWP_keep(),
840
			ecMulA_deep(n, ec_d, ec_deep, n),
841
			zzMul_deep(n / 2, n),
842 1
			zzMod_deep(n + n / 2 + 1, n));
843
}
844

845 1
err_t bignSign2(octet sig[], const bign_params* params, const octet oid_der[],
846
	size_t oid_len, const octet hash[], const octet privkey[], const void* t, 
847
	size_t t_len)
848
{
849
	err_t code;
850
	size_t no, n;
851
	// состояние (буферы могут пересекаться)
852
	void* state;
853
	ec_o* ec;				/* описание эллиптической кривой */
854
	word* d;				/* [n] личный ключ */
855
	word* k;				/* [n] одноразовый личный ключ */
856
	word* R;				/* [2n] точка R */
857
	word* s0;				/* [n/2] первая часть подписи */
858
	word* s1;				/* [n] вторая часть подписи */
859
	octet* hash_state;		/* [beltHash_keep] состояние хэширования */
860
	octet* stack;
861
	// проверить params
862 1
	if (!memIsValid(params, sizeof(bign_params)))
863 0
		return ERR_BAD_INPUT;
864 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
865 0
		return ERR_BAD_PARAMS;
866
	// проверить oid_der
867 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
868 0
		return ERR_BAD_OID;
869
	// проверить t
870 1
	if (!memIsNullOrValid(t, t_len))
871 0
		return ERR_BAD_INPUT;
872
	// создать состояние
873 1
	state = blobCreate(bignStart_keep(params->l, bignSign2_deep));
874 1
	if (state == 0)
875 0
		return ERR_OUTOFMEMORY;
876
	// старт
877 1
	code = bignStart(state, params);
878 1
	ERR_CALL_HANDLE(code, blobClose(state));
879 1
	ec = (ec_o*)state;
880
	// размерности
881 1
	no  = ec->f->no;
882 1
	n = ec->f->n;
883
	// проверить входные указатели
884 1
	if (!memIsValid(hash, no) ||
885 1
		!memIsValid(privkey, no) ||
886 1
		!memIsValid(sig, no + no / 2))
887
	{
888 0
		blobClose(state);
889 0
		return ERR_BAD_INPUT;
890
	}
891
	// раскладка состояния
892 1
	d = s1 = objEnd(ec, word);
893 1
	k = d + n;
894 1
	R = k + n;
895 1
	s0 = R + n + n / 2;
896 1
	hash_state = (octet*)(R + 2 * n);
897 1
	stack = hash_state + beltHash_keep();
898
	// загрузить d
899 1
	wwFrom(d, privkey, no);
900 1
	if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
901
	{
902 0
		blobClose(state);
903 0
		return ERR_BAD_PRIVKEY;
904
	}
905
	// хэшировать oid
906 1
	beltHashStart(hash_state);
907 1
	beltHashStepH(oid_der, oid_len, hash_state);
908
	// сгенерировать k по алгоритму 6.3.3
909
	{
910
		// theta <- belt-hash(oid || d || t)
911 1
		memCopy(stack, hash_state, beltHash_keep());
912 1
		beltHashStepH(privkey, no, stack);
913 1
		if (t != 0)
914 1
			beltHashStepH(t, t_len, stack);
915 1
		beltHashStepG(stack, stack);
916
		// инициализировать beltWBL ключом theta
917 1
		beltWBLStart(stack, stack, 32);
918
		// k <- H
919 1
		memCopy(k, hash, no);
920
		// k <- beltWBL(k, theta) пока k \notin {1,..., q - 1}
921
		while (1)
922
		{
923 1
			beltWBLStepE(k, no, stack);
924 1
			wwFrom(k, k, no);
925 1
			if (!wwIsZero(k, n) && wwCmp(k, ec->order, n) < 0)
926 1
				break;
927 0
			wwTo(k, no, k);
928
		}
929
	}
930
	// R <- k G
931 1
	if (!ecMulA(R, ec->base, ec, k, n, stack))
932
	{
933 0
		blobClose(state);
934 0
		return ERR_BAD_PARAMS;
935
	}
936 1
	qrTo((octet*)R, ecX(R), ec->f, stack);
937
	// s0 <- belt-hash(oid || R || H)
938 1
	beltHashStepH(R, no, hash_state);
939 1
	beltHashStepH(hash, no, hash_state);
940 1
	beltHashStepG2(sig, no / 2, hash_state);
941 1
	wwFrom(s0, sig, no / 2);
942
	// R <- (s0 + 2^l) d
943 1
	zzMul(R, s0, n / 2, d, n, stack);
944 1
	R[n + n / 2] = zzAdd(R + n / 2, R + n / 2, d, n);
945
	// s1 <- R mod q
946 1
	zzMod(s1, R, n + n / 2 + 1, ec->order, n, stack);
947
	// s1 <- (k - s1 - H) mod q
948 1
	zzSubMod(s1, k, s1, ec->order, n);
949 1
	wwFrom(k, hash, no);
950 1
	zzSubMod(s1, s1, k, ec->order, n);
951
	// выгрузить s1
952 1
	wwTo(sig + no / 2, no, s1);
953
	// все нормально
954 1
	blobClose(state);
955 1
	return ERR_OK;
956
}
957

958
/*
959
*******************************************************************************
960
Проверка ЭЦП
961
*******************************************************************************
962
*/
963

964 1
static size_t bignVerify_deep(size_t n, size_t f_deep, size_t ec_d,
965
	size_t ec_deep)
966
{
967 1
	return O_OF_W(4 * n) +
968 1
		utilMax(2,
969
			beltHash_keep(),
970 1
			ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1));
971
}
972

973 1
err_t bignVerify(const bign_params* params, const octet oid_der[],
974
	size_t oid_len, const octet hash[], const octet sig[], const octet pubkey[])
975
{
976
	err_t code;
977
	size_t no, n;
978
	// состояние (буферы могут пересекаться)
979
	void* state;
980
	ec_o* ec;			/* описание эллиптической кривой */	
981
	word* Q;			/* [2n] открытый ключ */
982
	word* R;			/* [2n] точка R */
983
	word* H;			/* [n] хэш-значение */
984
	word* s0;			/* [n / 2 + 1] первая часть подписи */
985
	word* s1;			/* [n] вторая часть подписи */
986
	octet* stack;
987
	// проверить params
988 1
	if (!memIsValid(params, sizeof(bign_params)))
989 0
		return ERR_BAD_INPUT;
990 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
991 0
		return ERR_BAD_PARAMS;
992
	// проверить oid_der
993 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
994 0
		return ERR_BAD_OID;
995
	// создать состояние
996 1
	state = blobCreate(bignStart_keep(params->l, bignVerify_deep));
997 1
	if (state == 0)
998 0
		return ERR_OUTOFMEMORY;
999
	// старт
1000 1
	code = bignStart(state, params);
1001 1
	ERR_CALL_HANDLE(code, blobClose(state));
1002 1
	ec = (ec_o*)state;
1003
	// размерности
1004 1
	no  = ec->f->no;
1005 1
	n = ec->f->n;
1006
	// проверить входные указатели
1007 1
	if (!memIsValid(hash, no) ||
1008 1
		!memIsValid(sig, no + no / 2) ||
1009 1
		!memIsValid(pubkey, 2 * no))
1010
	{
1011 0
		blobClose(state);
1012 0
		return ERR_BAD_INPUT;
1013
	}
1014
	// раскладка состояния
1015 1
	Q = R = objEnd(ec, word);
1016 1
	H = s0 = Q + 2 * n;
1017 1
	s1 = H + n;
1018 1
	stack = (octet*)(s1 + n);
1019
	// загрузить Q
1020 1
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
1021 1
		!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack))
1022
	{
1023 0
		blobClose(state);
1024 0
		return ERR_BAD_PUBKEY;
1025
	}
1026
	// загрузить и проверить s1
1027 1
	wwFrom(s1, sig + no / 2, O_OF_W(n));
1028 1
	if (wwCmp(s1, ec->order, n) >= 0)
1029
	{
1030 0
		blobClose(state);
1031 0
		return ERR_BAD_SIG;
1032
	}
1033
	// s1 <- (s1 + H) mod q
1034 1
	wwFrom(H, hash, no);
1035 1
	if (wwCmp(H, ec->order, n) >= 0)
1036
	{
1037 0
		zzSub2(H, ec->order, n);
1038
		// 2^{l - 1} < q < 2^l, H < 2^l => H - q < q
1039 0
		ASSERT(wwCmp(H, ec->order, n) < 0);
1040
	}
1041 1
	zzAddMod(s1, s1, H, ec->order, n);
1042
	// загрузить s0
1043 1
	wwFrom(s0, sig, no / 2);
1044 1
	s0[n / 2] = 1;
1045
	// R <- s1 G + (s0 + 2^l) Q
1046 1
	if (!ecAddMulA(R, ec, stack, 2, ec->base, s1, n, Q, s0, n / 2 + 1))
1047
	{
1048 0
		blobClose(state);
1049 0
		return ERR_BAD_SIG;
1050
	}
1051 1
	qrTo((octet*)R, ecX(R), ec->f, stack);
1052
	// s0 == belt-hash(oid || R || H)?
1053 1
	beltHashStart(stack);
1054 1
	beltHashStepH(oid_der, oid_len, stack);
1055 1
	beltHashStepH(R, no, stack);
1056 1
	beltHashStepH(hash, no, stack);
1057 1
	code = beltHashStepV2(sig, no / 2, stack) ? ERR_OK : ERR_BAD_SIG;
1058
	// завершение
1059 1
	blobClose(state);
1060 1
	return code;
1061
}
1062

1063
/*
1064
*******************************************************************************
1065
Создание токена
1066
*******************************************************************************
1067
*/
1068

1069 1
static size_t bignKeyWrap_deep(size_t n, size_t f_deep, size_t ec_d,
1070
	size_t ec_deep)
1071
{
1072 1
	return O_OF_W(3 * n) + 32 +
1073 1
		utilMax(2,
1074
			ecMulA_deep(n, ec_d, ec_deep, n),
1075
			beltKWP_keep());
1076
}
1077

1078 1
err_t bignKeyWrap(octet token[], const bign_params* params, const octet key[],
1079
	size_t len, const octet header[16], const octet pubkey[],
1080
	gen_i rng, void* rng_state)
1081
{
1082
	err_t code;
1083
	size_t no, n;
1084
	// состояние
1085
	void* state;
1086
	ec_o* ec;				/* описание эллиптической кривой */
1087
	word* k;				/* [n] одноразовый личный ключ */
1088
	word* R;				/* [2n] точка R */
1089
	octet* theta;			/* [32] ключ защиты */
1090
	octet* stack;
1091
	// проверить params
1092 1
	if (!memIsValid(params, sizeof(bign_params)))
1093 0
		return ERR_BAD_INPUT;
1094 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1095 0
		return ERR_BAD_PARAMS;
1096
	// проверить rng
1097 1
	if (rng == 0)
1098 0
		return ERR_BAD_RNG;
1099
	// проверить header и key
1100 1
	if (len < 16 ||
1101 1
		!memIsValid(key, len) ||
1102 1
		!memIsNullOrValid(header, 16))
1103 0
		return ERR_BAD_INPUT;
1104
	// создать состояние
1105 1
	state = blobCreate(bignStart_keep(params->l, bignKeyWrap_deep));
1106 1
	if (state == 0)
1107 0
		return ERR_OUTOFMEMORY;
1108
	// старт
1109 1
	code = bignStart(state, params);
1110 1
	ERR_CALL_HANDLE(code, blobClose(state));
1111 1
	ec = (ec_o*)state;
1112
	// размерности
1113 1
	no  = ec->f->no;
1114 1
	n = ec->f->n;
1115
	// проверить входные указатели
1116 1
	if (!memIsValid(pubkey, 2 * no) ||
1117 1
		!memIsValid(token, 16 + no + len))
1118
	{
1119 0
		blobClose(state);
1120 0
		return ERR_BAD_INPUT;
1121
	}
1122
	// раскладка состояния
1123 1
	k = objEnd(ec, word);
1124 1
	R = k + n;
1125 1
	theta = (octet*)(R + 2 * n);
1126 1
	stack = theta + 32;
1127
	// сгенерировать k
1128 1
	if (!zzRandNZMod(k, ec->order, n, rng, rng_state))
1129
	{
1130 0
		blobClose(state);
1131 0
		return ERR_BAD_RNG;
1132
	}
1133
	// R <- k Q
1134 1
	if (!qrFrom(ecX(R), pubkey, ec->f, stack) ||
1135 1
		!qrFrom(ecY(R, n), pubkey + no, ec->f, stack))
1136
	{
1137 0
		blobClose(state);
1138 0
		return ERR_BAD_PUBKEY;
1139
	}
1140 1
	if (!ecMulA(R, R, ec, k, n, stack))
1141
	{
1142 0
		blobClose(state);
1143 0
		return ERR_BAD_PARAMS;
1144
	}
1145
	// theta <- <R>_{256}
1146 1
	qrTo(theta, ecX(R), ec->f, stack);
1147
	// R <- k G
1148 1
	if (!ecMulA(R, ec->base, ec, k, n, stack))
1149
	{
1150 0
		blobClose(state);
1151 0
		return ERR_BAD_PARAMS;
1152
	}
1153 1
	qrTo((octet*)R, ecX(R), ec->f, stack);
1154
	// сформировать блок для шифрования
1155
	// (буферы key, header и token могут пересекаться)
1156 1
	if (header)
1157 1
		memCopy(R + n, header, 16);
1158
	else
1159 0
		memSetZero(R + n, 16);
1160 1
	memMove(token + no, key, len);
1161 1
	memCopy(token + no + len, R + n, 16);
1162
	// зашифровать
1163 1
	beltKWPStart(stack, theta, 32);
1164 1
	beltKWPStepE(token + no, len + 16, stack);
1165
	// доопределить токен
1166 1
	memCopy(token, R, no);
1167
	// все нормально
1168 1
	blobClose(state);
1169 1
	return ERR_OK;
1170
}
1171

1172
/*
1173
*******************************************************************************
1174
Разбор токена
1175
*******************************************************************************
1176
*/
1177

1178 1
static size_t bignKeyUnwrap_deep(size_t n, size_t f_deep, size_t ec_d,
1179
	size_t ec_deep)
1180
{
1181 1
	return MAX2(O_OF_W(5 * n), 32 + 16) +
1182 1
		utilMax(3,
1183
			beltKWP_keep(),
1184
			qrPower_deep(n, n, f_deep),
1185
			ecMulA_deep(n, ec_d, ec_deep, n));
1186
}
1187

1188 1
err_t bignKeyUnwrap(octet key[], const bign_params* params, const octet token[], 
1189
	size_t len, const octet header[16], const octet privkey[])
1190
{
1191
	err_t code;
1192
	size_t no, n;
1193
	// состояние (буферы могут пересекаться)
1194
	void* state;
1195
	ec_o* ec;				/* описание эллиптической кривой */
1196
	word* d;				/* [n] личный ключ */
1197
	word* R;				/* [2n] точка R */
1198
	word* t1;				/* [n] вспомогательное число */
1199
	word* t2;				/* [n] вспомогательное число */
1200
	octet* theta;			/* [32] ключ защиты */
1201
	octet* header2;			/* [16] заголовок2 */
1202
	void* stack;			/* граница стека */
1203
	// проверить params
1204 1
	if (!memIsValid(params, sizeof(bign_params)))
1205 0
		return ERR_BAD_INPUT;
1206 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1207 0
		return ERR_BAD_PARAMS;
1208
	// проверить token и header
1209 1
	if (!memIsValid(token, len) ||
1210 1
		!memIsNullOrValid(header, 16))
1211 0
		return ERR_BAD_INPUT;
1212
	// создать состояние
1213 1
	state = blobCreate(bignStart_keep(params->l, bignKeyUnwrap_deep));
1214 1
	if (state == 0)
1215 0
		return ERR_OUTOFMEMORY;
1216
	// старт
1217 1
	code = bignStart(state, params);
1218 1
	ERR_CALL_HANDLE(code, blobClose(state));
1219 1
	ec = (ec_o*)state;
1220
	// размерности
1221 1
	no  = ec->f->no;
1222 1
	n = ec->f->n;
1223
	// проверить длину токена
1224 1
	if (len < 32 + no)
1225
	{
1226 0
		blobClose(state);
1227 0
		return ERR_BAD_KEYTOKEN;
1228
	}
1229
	// проверить входные указатели
1230 1
	if (!memIsValid(privkey, no) ||
1231 1
		!memIsValid(key, len - 16 - no))
1232
	{
1233 0
		blobClose(state);
1234 0
		return ERR_BAD_INPUT;
1235
	}
1236
	// раскладка состояния
1237 1
	d = objEnd(ec, word);
1238 1
	R = d + n;
1239 1
	t1 = R + 2 * n;
1240 1
	t2 = t1 + n;
1241 1
	theta = (octet*)d;
1242 1
	header2 = theta + 32;
1243 1
	if (5 * no >= 48)
1244 1
		stack = t2 + n;
1245
	else
1246 0
		stack = header2 + 16;
1247
	// загрузить d
1248 1
	wwFrom(d, privkey, no);
1249 1
	if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0)
1250
	{
1251 0
		blobClose(state);
1252 0
		return ERR_BAD_PRIVKEY;
1253
	}
1254
	// xR <- x
1255 1
	if (!qrFrom(R, token, ec->f, stack))
1256
	{
1257 0
		blobClose(state);
1258 0
		return ERR_BAD_KEYTOKEN;
1259
	}
1260
	// t1 <- x^3 + a x + b
1261 1
	qrSqr(t1, R, ec->f, stack);
1262 1
	zmAdd(t1, t1, ec->A, ec->f);
1263 1
	qrMul(t1, t1, R, ec->f, stack);
1264 1
	zmAdd(t1, t1, ec->B, ec->f);
1265
	// yR <- t1^{(p + 1) / 4}
1266 1
	wwCopy(R + n, ec->f->mod, n);
1267 1
	zzAddW2(R + n, n, 1);
1268 1
	wwShLo(R + n, n, 2);
1269 1
	qrPower(R + n, t1, R + n, n, ec->f, stack);
1270
	// t2 <- yR^2
1271 1
	qrSqr(t2, R + n, ec->f, stack);
1272
	// (xR, yR) на кривой? t1 == t2?
1273 1
	if (!wwEq(t1, t2, n))
1274
	{
1275 0
		blobClose(state);
1276 0
		return ERR_BAD_KEYTOKEN;
1277
	}
1278
	// R <- d R
1279 1
	if (!ecMulA(R, R, ec, d, n, stack))
1280
	{
1281 0
		blobClose(state);
1282 0
		return ERR_BAD_PARAMS;
1283
	}
1284
	// theta <- <R>_{256}
1285 1
	qrTo(theta, ecX(R), ec->f, stack);
1286
	// сформировать данные для расшифрования
1287 1
	memCopy(key, token + no, len - no - 16);
1288 1
	memCopy(header2, token + len - 16, 16);
1289
	// расшифровать
1290 1
	beltKWPStart(stack, theta, 32);
1291 1
	beltKWPStepD2(key, header2, len - no, stack);
1292
	// проверить целостность
1293 1
	if (header && !memEq(header, header2, 16) ||
1294 0
		header == 0 && !memIsZero(header2, 16))
1295
	{
1296 0
		memSetZero(key, len - no - 16);
1297 0
		code = ERR_BAD_KEYTOKEN;
1298
	}
1299
	// завершение
1300 1
	blobClose(state);
1301 1
	return code;
1302
}
1303

1304
/*
1305
*******************************************************************************
1306
Извлечение ключей идентификационной ЭЦП
1307
*******************************************************************************
1308
*/
1309

1310 1
static size_t bignIdExtract_deep(size_t n, size_t f_deep, size_t ec_d,
1311
	size_t ec_deep)
1312
{
1313 1
	return O_OF_W(4 * n) +
1314 1
		utilMax(2,
1315
			beltHash_keep(),
1316 1
			ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1));
1317
}
1318

1319 1
err_t bignIdExtract(octet id_privkey[], octet id_pubkey[], 
1320
	const bign_params* params, const octet oid_der[], size_t oid_len,
1321
	const octet id_hash[], const octet sig[], octet pubkey[])
1322
{
1323
	err_t code;
1324
	size_t no, n;
1325
	// состояние (буферы могут пересекаться)
1326
	void* state;
1327
	ec_o* ec;			/* описание эллиптической кривой */
1328
	word* Q;			/* [2n] открытый ключ */
1329
	word* R;			/* [2n] точка R */
1330
	word* H;			/* [n] хэш-значение */
1331
	word* s0;			/* [n / 2 + 1] первая часть подписи */
1332
	word* s1;			/* [n] вторая часть подписи */
1333
	octet* stack;
1334
	// проверить params
1335 1
	if (!memIsValid(params, sizeof(bign_params)))
1336 0
		return ERR_BAD_INPUT;
1337 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1338 0
		return ERR_BAD_PARAMS;
1339
	// проверить oid_der
1340 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
1341 0
		return ERR_BAD_OID;
1342
	// создать состояние
1343 1
	state = blobCreate(bignStart_keep(params->l, bignIdExtract_deep));
1344 1
	if (state == 0)
1345 0
		return ERR_OUTOFMEMORY;
1346
	// старт
1347 1
	code = bignStart(state, params);
1348 1
	ERR_CALL_HANDLE(code, blobClose(state));
1349 1
	ec = (ec_o*)state;
1350
	// размерности
1351 1
	no  = ec->f->no;
1352 1
	n = ec->f->n;
1353
	// проверить входные указатели
1354 1
	if (!memIsValid(id_hash, no) ||
1355 1
		!memIsValid(sig, no + no / 2) ||
1356 1
		!memIsValid(pubkey, 2 * no) ||
1357 1
		!memIsValid(id_privkey, no) ||
1358 1
		!memIsValid(id_pubkey, 2 * no))
1359
	{
1360 0
		blobClose(state);
1361 0
		return ERR_BAD_INPUT;
1362
	}
1363
	// раскладка состояния
1364 1
	Q = R = objEnd(ec, word);
1365 1
	H = s0 = Q + 2 * n;
1366 1
	s1 = H + n;
1367 1
	stack = (octet*)(s1 + n);
1368
	// загрузить Q
1369 1
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
1370 1
		!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack))
1371
	{
1372 0
		blobClose(state);
1373 0
		return ERR_BAD_PUBKEY;
1374
	}
1375
	// загрузить и проверить s1
1376 1
	wwFrom(s1, sig + no / 2, no);
1377 1
	if (wwCmp(s1, ec->order, n) >= 0)
1378
	{
1379 0
		blobClose(state);
1380 0
		return ERR_BAD_SIG;
1381
	}
1382
	// s1 <- (s1 + H) mod q
1383 1
	wwFrom(H, id_hash, no);
1384 1
	if (wwCmp(H, ec->order, n) >= 0)
1385
	{
1386 0
		zzSub2(H, ec->order, n);
1387
		// 2^{l - 1} < q < 2^l, H < 2^l => H - q < q
1388 0
		ASSERT(wwCmp(H, ec->order, n) < 0);
1389
	}
1390 1
	zzAddMod(s1, s1, H, ec->order, n);
1391
	// загрузить s0
1392 1
	wwFrom(s0, sig, no);
1393 1
	s0[n / 2] = 1;
1394
	// R <- s1 G + (s0 + 2^l) Q
1395 1
	if (!ecAddMulA(R, ec, stack, 2, ec->base, s1, n, Q, s0, n / 2 + 1))
1396
	{
1397 0
		blobClose(state);
1398 0
		return ERR_BAD_SIG;
1399
	}
1400 1
	qrTo((octet*)R, ecX(R), ec->f, stack);
1401
	// s0 == belt-hash(oid || R || H)?
1402 1
	beltHashStart(stack);
1403 1
	beltHashStepH(oid_der, oid_len, stack);
1404 1
	beltHashStepH(R, no, stack);
1405 1
	beltHashStepH(id_hash, no, stack);
1406 1
	if (beltHashStepV2(sig, no / 2, stack))
1407
	{
1408 1
		wwTo(id_privkey, no, s1);
1409 1
		memCopy(id_pubkey, R, no);
1410 1
		qrTo(id_pubkey + no, ecY(R, n), ec->f, stack);
1411
	}
1412
	else
1413 0
		code = ERR_BAD_SIG;
1414
	// завершение
1415 1
	blobClose(state);
1416 1
	return code;
1417
}
1418

1419
/*
1420
*******************************************************************************
1421
Выработка идентификационной ЭЦП
1422
*******************************************************************************
1423
*/
1424

1425 1
static size_t bignIdSign_deep(size_t n, size_t f_deep, size_t ec_d,
1426
	size_t ec_deep)
1427
{
1428 1
	return O_OF_W(4 * n) +
1429 1
		utilMax(4,
1430
			beltHash_keep(),
1431
			ecMulA_deep(n, ec_d, ec_deep, n),
1432
			zzMul_deep(n / 2, n),
1433 1
			zzMod_deep(n + n / 2 + 1, n));
1434
}
1435

1436 1
err_t bignIdSign(octet id_sig[], const bign_params* params, 
1437
	const octet oid_der[], size_t oid_len, const octet id_hash[], 
1438
	const octet hash[], const octet id_privkey[], gen_i rng, void* rng_state)
1439
{
1440
	err_t code;
1441
	size_t no, n;
1442
	// состояние (буферы могут пересекаться)
1443
	void* state;
1444
	ec_o* ec;				/* описание эллиптической кривой */
1445
	word* e;				/* [n] личный ключ */
1446
	word* k;				/* [n] одноразовый личный ключ */
1447
	word* V;				/* [2n] точка V */
1448
	word* s0;				/* [n/2] первая часть подписи */
1449
	word* s1;				/* [n] вторая часть подписи */
1450
	octet* stack;
1451
	// проверить params
1452 1
	if (!memIsValid(params, sizeof(bign_params)))
1453 0
		return ERR_BAD_INPUT;
1454 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1455 0
		return ERR_BAD_PARAMS;
1456
	// проверить oid_der
1457 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
1458 0
		return ERR_BAD_OID;
1459
	// проверить rng
1460 1
	if (rng == 0)
1461 0
		return ERR_BAD_RNG;
1462
	// создать состояние
1463 1
	state = blobCreate(bignStart_keep(params->l, bignIdSign_deep));
1464 1
	if (state == 0)
1465 0
		return ERR_OUTOFMEMORY;
1466
	// старт
1467 1
	code = bignStart(state, params);
1468 1
	ERR_CALL_HANDLE(code, blobClose(state));
1469 1
	ec = (ec_o*)state;
1470
	// размерности
1471 1
	no  = ec->f->no;
1472 1
	n = ec->f->n;
1473
	// проверить входные указатели
1474 1
	if (!memIsValid(id_hash, no) ||
1475 1
		!memIsValid(hash, no) ||
1476 1
		!memIsValid(id_privkey, no) ||
1477 1
		!memIsValid(id_sig, no + no / 2))
1478
	{
1479 0
		blobClose(state);
1480 0
		return ERR_BAD_INPUT;
1481
	}
1482
	// раскладка состояния
1483 1
	e = s1 = objEnd(ec, word);
1484 1
	k = e + n;
1485 1
	V = k + n;
1486 1
	s0 = V + n + n / 2;
1487 1
	stack = (octet*)(V + 2 * n);
1488
	// загрузить e
1489 1
	wwFrom(e, id_privkey, no);
1490 1
	if (wwCmp(e, ec->order, n) >= 0)
1491
	{
1492 0
		blobClose(state);
1493 0
		return ERR_BAD_PRIVKEY;
1494
	}
1495
	// сгенерировать k с помощью rng
1496 1
	if (!zzRandNZMod(k, ec->order, n, rng, rng_state))
1497
	{
1498 0
		blobClose(state);
1499 0
		return ERR_BAD_RNG;
1500
	}
1501
	// V <- k G
1502 1
	if (!ecMulA(V, ec->base, ec, k, n, stack))
1503
	{
1504 0
		blobClose(state);
1505 0
		return ERR_BAD_PARAMS;
1506
	}
1507 1
	qrTo((octet*)V, ecX(V), ec->f, stack);
1508
	// s0 <- belt-hash(oid || V || H0 || H)
1509 1
	beltHashStart(stack);
1510 1
	beltHashStepH(oid_der, oid_len, stack);
1511 1
	beltHashStepH(V, no, stack);
1512 1
	beltHashStepH(id_hash, no, stack);
1513 1
	beltHashStepH(hash, no, stack);
1514 1
	beltHashStepG2(id_sig, no / 2, stack);
1515 1
	wwFrom(s0, id_sig, no / 2);
1516
	// V <- (s0 + 2^l) e
1517 1
	zzMul(V, s0, n / 2, e, n, stack);
1518 1
	V[n + n / 2] = zzAdd(V + n / 2, V + n / 2, e, n);
1519
	// s1 <- V mod q
1520 1
	zzMod(s1, V, n + n / 2 + 1, ec->order, n, stack);
1521
	// s1 <- (k - s1 - H) mod q
1522 1
	zzSubMod(s1, k, s1, ec->order, n);
1523 1
	wwFrom(k, hash, no);
1524 1
	zzSubMod(s1, s1, k, ec->order, n);
1525
	// выгрузить s1
1526 1
	wwTo(id_sig + no / 2, no, s1);
1527
	// все нормально
1528 1
	blobClose(state);
1529 1
	return ERR_OK;
1530
}
1531

1532 1
static size_t bignIdSign2_deep(size_t n, size_t f_deep, size_t ec_d,
1533
	size_t ec_deep)
1534
{
1535 1
	return O_OF_W(4 * n) + beltHash_keep() +
1536 1
		utilMax(5,
1537
			beltHash_keep(),
1538
			beltKWP_keep(),
1539
			ecMulA_deep(n, ec_d, ec_deep, n),
1540
			zzMul_deep(n / 2, n),
1541 1
			zzMod_deep(n + n / 2 + 1, n));
1542
}
1543

1544 1
err_t bignIdSign2(octet id_sig[], const bign_params* params, 
1545
	const octet oid_der[], size_t oid_len, const octet id_hash[], 
1546
	const octet hash[], const octet id_privkey[], const void* t, size_t t_len)
1547
{
1548
	err_t code;
1549
	size_t no, n;
1550
	// состояние (буферы могут пересекаться)
1551
	void* state;
1552
	ec_o* ec;				/* описание эллиптической кривой */
1553
	word* e;				/* [n] личный ключ */
1554
	word* k;				/* [n] одноразовый личный ключ */
1555
	word* V;				/* [2n] точка V */
1556
	word* s0;				/* [n/2] первая часть подписи */
1557
	word* s1;				/* [n] вторая часть подписи */
1558
	octet* hash_state;		/* [beltHash_keep] состояние хэширования */
1559
	octet* stack;
1560
	// проверить params
1561 1
	if (!memIsValid(params, sizeof(bign_params)))
1562 0
		return ERR_BAD_INPUT;
1563 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1564 0
		return ERR_BAD_PARAMS;
1565
	// проверить oid_der
1566 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
1567 0
		return ERR_BAD_OID;
1568
	// проверить t
1569 1
	if (!memIsNullOrValid(t, t_len))
1570 0
		return ERR_BAD_INPUT;
1571
	// создать состояние
1572 1
	state = blobCreate(bignStart_keep(params->l, bignIdSign2_deep));
1573 1
	if (state == 0)
1574 0
		return ERR_OUTOFMEMORY;
1575
	// старт
1576 1
	code = bignStart(state, params);
1577 1
	ERR_CALL_HANDLE(code, blobClose(state));
1578 1
	ec = (ec_o*)state;
1579
	// размерности
1580 1
	no  = ec->f->no;
1581 1
	n = ec->f->n;
1582
	// проверить входные указатели
1583 1
	if (!memIsValid(id_hash, no) ||
1584 1
		!memIsValid(hash, no) ||
1585 1
		!memIsValid(id_privkey, no) ||
1586 1
		!memIsValid(id_sig, no + no / 2))
1587
	{
1588 0
		blobClose(state);
1589 0
		return ERR_BAD_INPUT;
1590
	}
1591
	// раскладка состояния
1592 1
	e = s1 = objEnd(ec, word);
1593 1
	k = e + n;
1594 1
	V = k + n;
1595 1
	s0 = V + n + n / 2;
1596 1
	hash_state = (octet*)(V + 2 * n);
1597 1
	stack = hash_state + beltHash_keep();
1598
	// загрузить e
1599 1
	wwFrom(e, id_privkey, no);
1600 1
	if (wwCmp(e, ec->order, n) >= 0)
1601
	{
1602 0
		blobClose(state);
1603 0
		return ERR_BAD_PRIVKEY;
1604
	}
1605
	// хэшировать oid
1606 1
	beltHashStart(hash_state);
1607 1
	beltHashStepH(oid_der, oid_len, hash_state);
1608
	// сгенерировать k по алгоритму 6.3.3
1609
	{
1610
		// theta <- belt-hash(oid || e || t)
1611 1
		memCopy(stack, hash_state, beltHash_keep());
1612 1
		beltHashStepH(id_privkey, no, stack);
1613 1
		if (t != 0)
1614 0
			beltHashStepH(t, t_len, stack);
1615 1
		beltHashStepG(stack, stack);
1616
		// инициализировать beltWBL ключом theta
1617 1
		beltWBLStart(stack, stack, 32);
1618
		// k <- H
1619 1
		memCopy(k, hash, no);
1620
		// k <- beltWBL(k, theta) пока k \notin {1,..., q - 1}
1621
		while (1)
1622
		{
1623 1
			beltWBLStepE(k, no, stack);
1624 1
			wwFrom(k, k, no);
1625 1
			if (!wwIsZero(k, n) && wwCmp(k, ec->order, n) < 0)
1626 1
				break;
1627 0
			wwTo(k, no, k);
1628
		}
1629
	}
1630
	// V <- k G
1631 1
	if (!ecMulA(V, ec->base, ec, k, n, stack))
1632
	{
1633 0
		blobClose(state);
1634 0
		return ERR_BAD_PARAMS;
1635
	}
1636 1
	qrTo((octet*)V, ecX(V), ec->f, stack);
1637
	// s0 <- belt-hash(oid || V || H0 || H)
1638 1
	beltHashStepH(V, no, hash_state);
1639 1
	beltHashStepH(id_hash, no, hash_state);
1640 1
	beltHashStepH(hash, no, hash_state);
1641 1
	beltHashStepG2(id_sig, no / 2, hash_state);
1642 1
	wwFrom(s0, id_sig, no / 2);
1643
	// V <- (s0 + 2^l) e
1644 1
	zzMul(V, s0, n / 2, e, n, stack);
1645 1
	V[n + n / 2] = zzAdd(V + n / 2, V + n / 2, e, n);
1646
	// s1 <- V mod q
1647 1
	zzMod(s1, V, n + n / 2 + 1, ec->order, n, stack);
1648
	// s1 <- (k - s1 - H) mod q
1649 1
	zzSubMod(s1, k, s1, ec->order, n);
1650 1
	wwFrom(k, hash, no);
1651 1
	zzSubMod(s1, s1, k, ec->order, n);
1652
	// выгрузить s1
1653 1
	wwTo(id_sig + no / 2, no, s1);
1654
	// все нормально
1655 1
	blobClose(state);
1656 1
	return ERR_OK;
1657
}
1658

1659
/*
1660
*******************************************************************************
1661
Проверка идентификационной ЭЦП
1662
*******************************************************************************
1663
*/
1664

1665 1
static size_t bignIdVerify_deep(size_t n, size_t f_deep, size_t ec_d,
1666
	size_t ec_deep)
1667
{
1668 1
	return O_OF_W(7 * n + 2) + beltHash_keep() +
1669 1
		utilMax(5,
1670
			beltHash_keep(),
1671
			ecpIsOnA_deep(n, f_deep),
1672
			zzMul_deep(n / 2, n / 2),
1673
			zzMod_deep(n + 1, n),
1674 1
			ecAddMulA_deep(n, ec_d, ec_deep, 3, n, n / 2 + 1, n));
1675
}
1676

1677 1
err_t bignIdVerify(const bign_params* params, const octet oid_der[], 
1678
	size_t oid_len, const octet* id_hash, const octet* hash, 
1679
	const octet id_sig[], const octet id_pubkey[], const octet pubkey[])
1680
{
1681
	err_t code;
1682
	size_t no, n;
1683
	// состояние (буферы R и V совпадают)
1684
	void* state;
1685
	ec_o* ec;			/* описание эллиптической кривой */	
1686
	word* R;			/* [2n] открытый ключ R */
1687
	word* Q;			/* [2n] открытый ключ Q */
1688
	word* V;			/* [2n] точка V (V == R) */
1689
	word* s0;			/* [n / 2 + 1] первая часть подписи */
1690
	word* s1;			/* [n] вторая часть подписи */
1691
	word* t;			/* [n / 2] переменная t */
1692
	word* t1;			/* [n + 1] произведение (s0 + 2^l)(t + 2^l) */
1693
	octet* hash_state;	/* [beltHash_keep] состояние хэширования */
1694
	octet* stack;
1695
	// проверить params
1696 1
	if (!memIsValid(params, sizeof(bign_params)))
1697 0
		return ERR_BAD_INPUT;
1698 1
	if (params->l != 128 && params->l != 192 && params->l != 256)
1699 0
		return ERR_BAD_PARAMS;
1700
	// проверить oid_der
1701 1
	if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len)  == SIZE_MAX)
1702 0
		return ERR_BAD_OID;
1703
	// создать состояние
1704 1
	state = blobCreate(bignStart_keep(params->l, bignIdVerify_deep));
1705 1
	if (state == 0)
1706 0
		return ERR_OUTOFMEMORY;
1707
	// старт
1708 1
	code = bignStart(state, params);
1709 1
	ERR_CALL_HANDLE(code, blobClose(state));
1710 1
	ec = (ec_o*)state;
1711
	// размерности
1712 1
	no  = ec->f->no;
1713 1
	n = ec->f->n;
1714
	// проверить входные указатели
1715 1
	if (!memIsValid(id_hash, no) ||
1716 1
		!memIsValid(hash, no) ||
1717 1
		!memIsValid(id_sig, no + no / 2) ||
1718 1
		!memIsValid(id_pubkey, 2 * no) ||
1719 1
		!memIsValid(pubkey, 2 * no))
1720
	{
1721 0
		blobClose(state);
1722 0
		return ERR_BAD_INPUT;
1723
	}
1724
	// раскладка состояния
1725 1
	R = V = objEnd(ec, word);
1726 1
	Q = R + 2 * n;
1727 1
	s0 = Q + 2 * n;
1728 1
	s1 = s0 + n / 2 + 1;
1729 1
	t = s1 + n;
1730 1
	t1 = t + n / 2;
1731 1
	hash_state = (octet*)(t1 + n + 1);
1732 1
	stack = hash_state + beltHash_keep();
1733
	// загрузить R
1734 1
	if (!qrFrom(ecX(R), id_pubkey, ec->f, stack) ||
1735 1
		!qrFrom(ecY(R, n), id_pubkey + no, ec->f, stack) ||
1736 1
		!ecpIsOnA(R, ec, stack))
1737
	{
1738 1
		blobClose(state);
1739 1
		return ERR_BAD_PUBKEY;
1740
	}
1741
	// загрузить Q
1742 1
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
1743 1
		!qrFrom(ecY(Q, n), pubkey + no, ec->f, stack))
1744
	{
1745 0
		blobClose(state);
1746 0
		return ERR_BAD_PUBKEY;
1747
	}
1748
	// загрузить и проверить s1
1749 1
	wwFrom(s1, id_sig + no / 2, no);
1750 1
	if (wwCmp(s1, ec->order, n) >= 0)
1751
	{
1752 0
		blobClose(state);
1753 0
		return ERR_BAD_SIG;
1754
	}
1755
	// s1 <- (s1 + H) mod q
1756 1
	wwFrom(t, hash, no);
1757 1
	if (wwCmp(t, ec->order, n) >= 0)
1758
	{
1759 0
		zzSub2(t, ec->order, n);
1760
		// 2^{l - 1} < q < 2^l, H < 2^l => H - q < q
1761 0
		ASSERT(wwCmp(t, ec->order, n) < 0);
1762
	}
1763 1
	zzAddMod(s1, s1, t, ec->order, n);
1764
	// загрузить s0
1765 1
	wwFrom(s0, id_sig, no / 2);
1766 1
	s0[n / 2] = 1;
1767
	// belt-hash(oid...)
1768 1
	beltHashStart(hash_state);
1769 1
	beltHashStepH(oid_der, oid_len, hash_state);
1770
	// t <- belt-hash(oid || R || H0)
1771 1
	memCopy(stack, hash_state, beltHash_keep());
1772 1
	beltHashStepH(id_pubkey, no, stack);
1773 1
	beltHashStepH(id_hash, no, stack);
1774 1
	beltHashStepG2((octet*)t, no / 2, stack);
1775 1
	wwFrom(t, t, no / 2);
1776
	// t1 <- -(t + 2^l)(s0 + 2^l) mod q
1777 1
	zzMul(t1, t, n / 2, s0, n / 2, stack);
1778 1
	t1[n] = zzAdd2(t1 + n / 2, t, n / 2);
1779 1
	t1[n] += zzAdd2(t1 + n / 2, s0, n / 2);
1780 1
	++t1[n];
1781 1
	zzMod(t1, t1, n + 1, ec->order, n, stack);
1782 1
	zzNegMod(t1, t1, ec->order, n);
1783
	// V <- s1 G + (s0 + 2^l) R + t Q
1784 1
	if (!ecAddMulA(V, ec, stack,
1785 1
		3, ec->base, s1, n, R, s0, n / 2 + 1, Q, t1, n))
1786
	{
1787 0
		blobClose(state);
1788 0
		return ERR_BAD_SIG;
1789
	}
1790 1
	qrTo((octet*)V, ecX(V), ec->f, stack);
1791
	// s0 == belt-hash(oid || V || H0 || H)?
1792 1
	beltHashStepH(V, no, hash_state);
1793 1
	beltHashStepH(id_hash, no, hash_state);
1794 1
	beltHashStepH(hash, no, hash_state);
1795 1
	code = beltHashStepV2(id_sig, no / 2, hash_state) ? ERR_OK : ERR_BAD_SIG;
1796
	// завершение
1797 1
	blobClose(state);
1798 1
	return code;
1799
}

Read our documentation on viewing source code .

Loading