Exemple #1
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuValPoint(const dstu_params* params, const octet point[])
{
	err_t code;
	// состояние
	ec_o* ec;
	word* x;
	word* y;
	void* stack;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuValPoint_deep);
	ERR_CALL_CHECK(code);
	// проверить входные указатели
	if (!memIsValid(point, 2 * ec->f->no))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	x = objEnd(ec, word);
	y = x + ec->f->n;
	stack = y + ec->f->n;
	// (x, y) лежит на ЭК? (x, y) имеет порядок order?
	if (!qrFrom(x, point, ec->f, stack) ||
		!qrFrom(y, point + ec->f->no, ec->f, stack) ||
		!ec2IsOnA(x, ec, stack) ||
		!ecHasOrderA(x, ec, ec->order, ec->f->n, stack))
		code = ERR_BAD_POINT;
	// завершение
	_dstuCloseEc(ec);
	return code;
}
Exemple #2
0
static err_t beeSelfCheck()
{
	// характеристики
	octet stampRead[STAMP_SIZE], stampCalc[STAMP_SIZE];
	err_t code = beeReadAndCalcStamp(stampRead, stampCalc);
	ERR_CALL_CHECK(code);
	// сравнить
	return memEq(stampRead, stampCalc, STAMP_SIZE) ? ERR_OK : ERR_BAD_HASH;
}
Exemple #3
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuGenPoint(octet point[], const dstu_params* params, gen_i rng, 
	void* rng_state)
{
	err_t code;
	// состояние
	ec_o* ec;
	word* x;
	word* y;
	word* t;
	void* stack;
	// проверить rng
	if (rng == 0)
		return ERR_BAD_RNG;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuGenPoint_deep);
	ERR_CALL_CHECK(code);
	// проверить входные указатели
	if (!memIsValid(point, 2 * ec->f->no))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	x = objEnd(ec, word);
	y = x + ec->f->n;
	t = y + ec->f->n;
	stack = t + ec->f->n;
	// пока точка не сгенерирована
	while (1)
	{
		// сгенерировать x-координату
		// [алгоритм из раздела 6.4 ДСТУ --- обрезка x]
		rng(x, ec->f->no, rng_state);
		wwFrom(x, x, ec->f->no);
		wwTrimHi(x, ec->f->n, gf2Deg(ec->f));
		// y <- x^2
		qrSqr(y, x, ec->f, stack);
		// t <- x^3
		qrMul(t, x, y, ec->f, stack);
		// t <- x^3 + a x^2 + b
		if (!qrIsZero(ec->A, ec->f))
			gf2Add2(t, y, ec->f);
		gf2Add2(t, ec->B, ec->f);
		// y <- Solve[y^2 + x y == t], ord(x, y) == order?
		if (gf2QSolve(y, x, t, ec->f, stack) &&
			ecHasOrderA(x, ec, ec->order, ec->f->n, stack))
			break;
	}
	// выгрузить точку
	qrTo(point, x, ec->f, stack);
	qrTo(point + ec->f->no, y, ec->f, stack);
	// завершение
	_dstuCloseEc(ec);
	return ERR_OK;
}
Exemple #4
0
Fichier : g12s.c Projet : fars/bee2
err_t g12sGenKeypair(octet privkey[], octet pubkey[],
	const g12s_params* params, gen_i rng, void* rng_stack)
{
	err_t code;
	size_t m, mo;
	// состояние
	ec_o* ec;
	word* d;				/* [m] личный ключ */
	word* Q;				/* [2n] открытый ключ */	
	void* stack;
	// проверить rng
	if (rng == 0)
		return ERR_BAD_RNG;
	// старт
	code = g12sCreateEc(&ec, params, g12sGenKeypair_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	m = W_OF_B(params->l);
	mo = O_OF_B(params->l);
	// проверить входные указатели
	if (!memIsValid(privkey, mo) || 
		!memIsValid(pubkey, 2 * ec->f->no))
	{
		g12sCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	d = objEnd(ec, word);
	Q = d + m;
	stack = Q + 2 * ec->f->n;
	// d <-R {1,2,..., q - 1}
	if (!zzRandNZMod(d, ec->order, m, rng, rng_stack))
	{
		g12sCloseEc(ec);
		return ERR_BAD_RNG;
	}
	// Q <- d P
	if (!ecMulA(Q, ec->base, ec, d, m, stack))
	{
		g12sCloseEc(ec);
		return ERR_BAD_PARAMS;
	}
	// выгрузить ключи
	wwTo(privkey, mo, d);
	qrTo(pubkey, ecX(Q), ec->f, stack);
	qrTo(pubkey + ec->f->no, ecY(Q, ec->f->n), ec->f, stack);
	// все нормально
	g12sCloseEc(ec);
	return ERR_OK;
}
Exemple #5
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuCompressPoint(octet xpoint[], const dstu_params* params, 
	const octet point[])
{
	err_t code;
	// состояние
	ec_o* ec;
	word* x;
	word* y;
	void* stack;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuCompressPoint_deep);
	ERR_CALL_CHECK(code);
	// проверить входные указатели
	if (!memIsValid(point, 2 * ec->f->no) || 
		!memIsValid(xpoint, ec->f->no))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	x = objEnd(ec, word);
	y = x + ec->f->n;
	stack = y + ec->f->n;
	// загрузить точку
	if (!qrFrom(x, point, ec->f, stack) ||
		!qrFrom(y, point + ec->f->no, ec->f, stack))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_POINT;
	}
	// x == 0?
	if (wwIsZero(x, ec->f->n))
	{
		_dstuCloseEc(ec);
		return ERR_OK;
	}
	// y <- y / x
	qrDiv(y, y, x, ec->f, stack);
	// xpoint <- x(point), xpoint_0 <- tr(y)
	memMove(xpoint, point, ec->f->no);
	xpoint[0] &= 0xFE;
	xpoint[0] |= gf2Tr(y, ec->f, stack);
	// завершение
	_dstuCloseEc(ec);
	return ERR_OK;
}
Exemple #6
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuValParams(const dstu_params* params)
{
	err_t code;
	// состояние
	ec_o* ec;
	void* stack;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuValParams_deep);
	ERR_CALL_CHECK(code);
	stack = objEnd(ec, void);
	// проверить кривую и базовую точку
	if (wwBitSize(ec->order, ec->f->n) <= 160 ||
		!ec2IsValid(ec, stack) ||
		!ec2SeemsValidGroup(ec, stack) ||
		!ec2IsSafeGroup(ec, 32, stack) ||
		!ecHasOrderA(ec->base, ec, ec->order, ec->f->n, stack))
		code = ERR_BAD_PARAMS;
	// завершение
	_dstuCloseEc(ec);
	return code;
}
Exemple #7
0
Fichier : g12s.c Projet : fars/bee2
err_t g12sValParams(const g12s_params* params)
{
	err_t code;
	// состояние
	ec_o* ec;
	void* stack;
	// старт
	code = g12sCreateEc(&ec, params, g12sValParams_deep);
	ERR_CALL_CHECK(code);
	stack = objEnd(ec, void);
	// проверить кривую, проверить J(E)
	if (!ecpIsValid(ec, stack) ||
		!ecpSeemsValidGroup(ec, stack) ||
		!ecpIsSafeGroup(ec, params->l == 256 ? 31 : 131, stack) ||
		!ecHasOrderA(ec->base, ec, ec->order, ec->f->n, stack) ||
		qrIsZero(ec->A, ec->f) || 
		qrIsZero(ec->B, ec->f))
		code = ERR_BAD_PARAMS;
	// завершение
	g12sCloseEc(ec);
	return code;
}
Exemple #8
0
Fichier : g12s.c Projet : fars/bee2
err_t g12sVerify(const g12s_params* params, const octet hash[], 
	const octet sig[], const octet pubkey[])
{
	err_t code;
	size_t m, mo;
	// состояние
	ec_o* ec;
	word* Q;		/* [2n] открытый ключ / точка R */
	word* r;		/* [m] первая (старшая) часть подписи */
	word* s;		/* [m] вторая часть подписи */
	word* e;		/* [m] обработанное хэш-значение, v */
	void* stack;
	// старт
	code = g12sCreateEc(&ec, params, g12sVerify_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	m = W_OF_B(params->l);
	mo = O_OF_B(params->l);
	// проверить входные указатели
	if (!memIsValid(hash, mo) ||
		!memIsValid(sig, 2 * mo) ||
		!memIsValid(pubkey, 2 * ec->f->no))
	{
		g12sCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	Q = objEnd(ec, word);
	r = Q + 2 * ec->f->n;
	s = r + m;
	e = s + m;
	stack = e + m;
	// загрузить Q
	if (!qrFrom(ecX(Q), pubkey, ec->f, stack) ||
		!qrFrom(ecY(Q, ec->f->n), pubkey + ec->f->no, ec->f, stack))
	{
		g12sCloseEc(ec);
		return ERR_BAD_PUBKEY;
	}
	// загрузить r и s
	memCopy(s, sig + mo, mo);
	memRev(s, mo);
	wwFrom(s, s, mo);
	memCopy(r, sig, mo);
	memRev(r, mo);
	wwFrom(r, r, mo);
	if (wwIsZero(s, m) || 
		wwIsZero(r, m) || 
		wwCmp(s, ec->order, m) >= 0 ||
		wwCmp(r, ec->order, m) >= 0)
	{
		g12sCloseEc(ec);
		return ERR_BAD_SIG;
	}
	// e <- hash \mod q
	memCopy(e, hash, mo);
	memRev(e, mo);
	wwFrom(e, e, mo);
	zzMod(e, e, m, ec->order, m, stack);
	// e == 0 => e <- 1
	if (wwIsZero(e, m))
		e[0] = 1;
	// e <- e^{-1} \mod q [v]
	zzInvMod(e, e, ec->order, m, stack);
	// s <- s e \mod q [z1]
	zzMulMod(s, s, e, ec->order, m, stack);
	// e <- - e r \mod q [z2]
	zzMulMod(e, e, r, ec->order, m, stack);
	zzNegMod(e, e, ec->order, m);
	// Q <- s P + e Q [z1 P + z2 Q = R]
	if (!ecAddMulA(Q, ec, stack, 2, ec->base, s, m, Q, e, m))
	{
		g12sCloseEc(ec);
		return ERR_BAD_PARAMS;
	}
	// s <- x_Q \mod q [x_R \mod q]
	qrTo((octet*)Q, ecX(Q), ec->f, stack);
	wwFrom(Q, Q, ec->f->no);
	zzMod(s, Q, ec->f->n, ec->order, m, stack);
	// s == r?
	code = wwEq(r, s, m) ? ERR_OK : ERR_BAD_SIG;
	// завершение
	g12sCloseEc(ec);
	return code;
}
Exemple #9
0
Fichier : g12s.c Projet : fars/bee2
err_t g12sSign(octet sig[], const g12s_params* params, const octet hash[],
	const octet privkey[], gen_i rng, void* rng_stack)
{
	err_t code;
	size_t m, mo;
	// состояние
	ec_o* ec;
	word* d;		/* [m] личный ключ */
	word* e;		/* [m] обработанное хэш-значение */
	word* k;		/* [m] одноразовый ключ */
	word* C;		/* [2n] вспомогательная точка */
	word* r;		/* [m] первая (старшая) часть подписи */
	word* s;		/* [m] вторая часть подписи */
	void* stack;
	// проверить rng
	if (rng == 0)
		return ERR_BAD_RNG;
	// старт
	code = g12sCreateEc(&ec, params, g12sSign_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	m = W_OF_B(params->l);
	mo = O_OF_B(params->l);
	// проверить входные указатели
	if (!memIsValid(hash, mo) ||
		!memIsValid(privkey, mo) ||
		!memIsValid(sig, 2 * mo))
	{
		g12sCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	d = objEnd(ec, word);
	e = d + m;
	k = e + m;
	C = k + m;
	r = C + 2 * ec->f->n;
	s = r + m;
	stack = s + m;
	// загрузить d
	wwFrom(d, privkey, mo);
	if (wwIsZero(d, m) || 
		wwCmp(d, ec->order, m) >= 0)
	{
		g12sCloseEc(ec);
		return ERR_BAD_PRIVKEY;
	}
	// e <- hash \mod q
	memCopy(e, hash, mo);
	memRev(e, mo);
	wwFrom(e, e, mo);
	zzMod(e, e, m, ec->order, m, stack);
	// e == 0 => e <- 1
	if (wwIsZero(e, m))
		e[0] = 1;
	// k <-R {1,2,..., q - 1}
gen_k:
	if (!zzRandNZMod(k, ec->order, m, rng, rng_stack))
	{
		g12sCloseEc(ec);
		return ERR_BAD_RNG;
	}
	// C <- k P
	if (!ecMulA(C, ec->base, ec, k, m, stack))
	{
		// если params корректны, то этого быть не должно
		g12sCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// r <- x_C \mod q
	qrTo((octet*)C, ecX(C), ec->f, stack);
	wwFrom(r, C, ec->f->no);
	zzMod(r, r, ec->f->n, ec->order, m, stack);
	// r == 0 => повторить генерацию k
	if (wwIsZero(r, m))
		goto gen_k;
	// s <- (rd + ke) \mod q
	zzMulMod(k, k, e, ec->order, m, stack);
	zzMulMod(s, r, d, ec->order, m, stack);
	zzAddMod(s, s, k, ec->order, m);
	// выгрузить ЭЦП
	wwTo(sig, mo, s);
	wwTo(sig + mo, mo, r);
	memRev(sig, 2 * mo);
	// все нормально
	g12sCloseEc(ec);
	return ERR_OK;
}
Exemple #10
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuSign(octet sig[], const dstu_params* params, size_t ld, 
	const octet hash[], size_t hash_len, const octet privkey[], 
	gen_i rng, void* rng_state)
{
	err_t code;
	size_t order_n, order_no, order_nb;
	// состояние
	ec_o* ec;
	word* e;		/* эфемерный лк */
	word* h;		/* хэш-значение как элемент поля */
	word* x;		/* х-координата эфемерного ок */
	word* y;		/* y-координата эфемерного ок */
	word* r;		/* первая часть ЭЦП */
	word* s;		/* вторая часть ЭЦП */
	void* stack;
	// проверить rng
	if (rng == 0)
		return ERR_BAD_RNG;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuSign_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	order_nb = wwBitSize(ec->order, ec->f->n);
	order_no = O_OF_B(order_nb);
	order_n = W_OF_B(order_nb);
	// проверить входные указатели
	// шаги 1, 2: проверка params, privkey
	// шаг 3: проверить ld
	if (!memIsValid(privkey, order_no) || 
		ld % 16 != 0 || ld < 16 * order_no ||
		!memIsValid(hash, hash_len) ||
		!memIsValid(sig, O_OF_B(ld)))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	e = objEnd(ec, word);
	h = e + ec->f->n;
	x = h + ec->f->n;
	y = x + ec->f->n;
	r = y + ec->f->n;
	s = r + ec->f->n;
	stack = s + ec->f->n;
	// шаги 4 -- 6: хэширование
	// шаг 7: перевести hash в элемент основного поля h
	// [алгоритм из раздела 5.9 ДСТУ]
	if (hash_len < ec->f->no)
	{
		memCopy(h, hash, hash_len);
		memSetZero((octet*)h + hash_len, ec->f->no - hash_len);
	}
	else
	{
		memCopy(h, hash, ec->f->no);
		// memTrimHi(h, ec->f->no, gf2Deg(ec->f));
		((octet*)h)[ec->f->no - 1] &= (1 << gf2Deg(ec->f) % 8) - 1;
	}
	qrFrom(h, (octet*)h, ec->f, stack);
	// шаг 7: если h == 0, то h <- 1
	if (qrIsZero(h, ec->f))
		qrSetUnity(h, ec->f);
	// шаг 8: e <-R {1,2,..., order - 1}
	// [алгоритм из раздела 6.3 ДСТУ --- обрезка e]
step8:
	while (1)
	{
		rng(e, O_OF_B(order_nb), rng_state);
		wwFrom(e, e, O_OF_B(order_nb));
		wwTrimHi(e, order_n, order_nb - 1);
		ASSERT(wwCmp(e, ec->order, order_n) < 0);
		if (!wwIsZero(e, order_n))
			break;
	}
	// шаг 8: (x, y) <- e G
	if (!ecMulA(x, ec->base, ec, e, order_n, stack))
	{
		// если params корректны, то этого быть не должно
		_dstuCloseEc(ec);
		return ERR_BAD_PARAMS;
	}
	// шаг 8: если x == 0, то повторить генерацию
	if (qrIsZero(x, ec->f))
		goto step8;
	// шаг 9: y <- x * h
	qrMul(y, x, h, ec->f, stack);
	// шаг 10: r <- \bar{y}
	ASSERT(order_n <= ec->f->n);
	qrTo((octet*)r, y, ec->f, stack);
	wwFrom(r, r, order_no);
	wwTrimHi(r, order_n, order_nb - 1);
	// шаг 11: если r = 0, то повторить генерацию
	if (wwIsZero(r, order_n))
		goto step8;
	// шаг 12: s <- (e + dr) mod order
	wwFrom(s, privkey, order_no);
	zzMulMod(s, s, r, ec->order, order_n, stack);
	zzAddMod(s, s, e, ec->order, order_n);
	// шаг 13: если s = 0, то повторить генерацию
	if (wwIsZero(s, order_n))
		goto step8;
	// шаг 14: сформировать ЭЦП из r и s
	// [алгоритм из раздела 5.10 ДСТУ]
	memSetZero(sig, O_OF_B(ld));
	wwTo(sig, order_no, r);
	wwTo(sig + ld / 16, order_no, s);
	// все нормально
	_dstuCloseEc(ec);
	return code;
}
Exemple #11
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuGenKeypair(octet privkey[], octet pubkey[], 
	const dstu_params* params, gen_i rng, void* rng_state)
{
	err_t code;
	size_t order_n, order_no, order_nb;
	// состояние
	ec_o* ec;
	word* d;
	word* x;
	word* y;
	void* stack;
	// проверить rng
	if (rng == 0)
		return ERR_BAD_RNG;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuGenKeypair_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	order_nb = wwBitSize(ec->order, ec->f->n);
	order_no = O_OF_B(order_nb);
	order_n = W_OF_B(order_nb);
	// проверить входные указатели
	if (!memIsValid(privkey, order_no) || 
		!memIsValid(pubkey, 2 * ec->f->no))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	d = objEnd(ec, word);
	x = d + ec->f->n;
	y = x + ec->f->n;
	stack = y + ec->f->n;
	// d <-R {1,2,..., order - 1}
	// [алгоритм из раздела 6.3 ДСТУ --- обрезка d]
	wwSetZero(d, order_n);
	while (1)
	{
		rng(d, O_OF_B(order_nb), rng_state);
		wwFrom(d, d, O_OF_B(order_nb));
		wwTrimHi(d, order_n, order_nb - 1);
		ASSERT(wwCmp(d, ec->order, order_n) < 0);
		// 0 < d?
		if (!wwIsZero(d, order_n))
			break;
	}
	// Q <- d G
	if (!ecMulA(x, ec->base, ec, d, order_n, stack))
	{
		// если params корректны, то этого быть не должно
		_dstuCloseEc(ec);
		return ERR_BAD_PARAMS;
	}
	// Q <- -Q
	ec2NegA(x, x, ec);
	// выгрузить ключи
	wwTo(privkey, order_no, d);
	qrTo(pubkey, x, ec->f, stack);
	qrTo(pubkey + ec->f->no, y, ec->f, stack);
	// все нормально
	_dstuCloseEc(ec);
	return code;
}
Exemple #12
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuRecoverPoint(octet point[], const dstu_params* params, 
	const octet xpoint[])
{
	err_t code;
	register bool_t trace;
	// состояние
	ec_o* ec;
	word* x;
	word* y;
	void* stack;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuRecoverPoint_deep);
	ERR_CALL_CHECK(code);
	// проверить входные указатели
	if (!memIsValid(xpoint, ec->f->no) || 
		!memIsValid(point, 2 * ec->f->no))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	x = objEnd(ec, word);
	y = x + ec->f->n;
	stack = y + ec->f->n;
	// загрузить сжатое представление точки
	if (!qrFrom(x, xpoint, ec->f, stack))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_POINT;
	}
	// x == 0?
	if (qrIsZero(x, ec->f))
	{
		size_t m = gf2Deg(ec->f);
		// b <- b^{2^{m - 1}}
		while (--m)
			qrSqr(ec->B, ec->B, ec->f, stack);
		// выгрузить y-координату
		qrTo(point + ec->f->n, ec->B, ec->f, stack);
		// все нормально
		_dstuCloseEc(ec);
		return ERR_OK;
	}
	// восстановить первый разряд x
	trace = wwTestBit(x, 0);
	wwSetBit(x, 0, 0);
	if (gf2Tr(x, ec->f, stack) != (bool_t)params->A)
		wwSetBit(x, 0, 1);
	// y <- x + a + b / x^2
	qrSqr(y, x, ec->f, stack);
	qrDiv(y, ec->B, y, ec->f, stack);
	gf2Add2(y, x, ec->f);
	if (params->A)
		wwFlipBit(y, 0);
	// Solve[z^2 + z == y]
	if (!gf2QSolve(y, ec->f->unity, y, ec->f, stack))
	{
		trace = 0;
		_dstuCloseEc(ec);
		return ERR_BAD_PARAMS;
	}
	// tr(y) == trace?
	if (gf2Tr(y, ec->f, stack) == trace)
		// y <- y * x
		qrMul(y, x, y, ec->f, stack);
	else
		// y <- (y + 1) * x
		qrMul(y, x, y, ec->f, stack),
		gf2Add2(y, x, ec->f);
	// выгрузить точку
	qrTo(point, x, ec->f, stack);
	qrTo(point + ec->f->no, y, ec->f, stack);
	// все нормально
	trace = 0;
	_dstuCloseEc(ec);
	return code;
}
Exemple #13
0
Fichier : dstu.c Projet : fars/bee2
err_t dstuVerify(const dstu_params* params, size_t ld, const octet hash[], 
	size_t hash_len, const octet sig[], const octet pubkey[])
{
	err_t code;
	size_t order_n, order_no, order_nb, i;
	// состояние
	ec_o* ec;
	word* h;		/* хэш-значение как элемент поля */
	word* x;		/* х-координата эфемерного ок */
	word* y;		/* y-координата эфемерного ок */
	word* r;		/* первая часть ЭЦП */
	word* s;		/* вторая часть ЭЦП */
	void* stack;
	// старт
	code = _dstuCreateEc(&ec, params, _dstuVerify_deep);
	ERR_CALL_CHECK(code);
	// размерности order
	order_nb = wwBitSize(ec->order, ec->f->n);
	order_no = O_OF_B(order_nb);
	order_n = W_OF_B(order_nb);
	// проверить входные указатели
	// шаги 1, 2: обработка идентификатора хэш-функции
	// шаг 3: проверить ld
	if (!memIsValid(pubkey, 2 * ec->f->no) || 
		ld % 16 != 0 || ld < 16 * order_no ||
		!memIsValid(hash, hash_len))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_INPUT;
	}
	// раскладка состояния
	h = objEnd(ec, word);
	x = h + ec->f->n;
	y = x + ec->f->n;
	r = y + ec->f->n;
	s = r + ec->f->n;
	stack = s + ec->f->n;
	// шаг 4: проверить params
	// шаг 5: проверить pubkey
	// [минимальная проверка принадлежности координат базовому полю]
	if (!qrFrom(x, pubkey, ec->f, stack) || 
		!qrFrom(y, pubkey + ec->f->no, ec->f, stack))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_PUBKEY;
	}
	// шаги 6, 7: хэширование
	// шаг 8: перевести hash в элемент основного поля h
	// [алгоритм из раздела 5.9 ДСТУ]
	if (hash_len < ec->f->no)
	{
		memCopy(h, hash, hash_len);
		memSetZero((octet*)h + hash_len, ec->f->no - hash_len);
	}
	else
	{
		memCopy(h, hash, ec->f->no);
		// memTrimHi(h, ec->f->no, gf2Deg(ec->f));
		((octet*)h)[ec->f->no - 1] &= (1 << gf2Deg(ec->f) % 8) - 1;
	}
	qrFrom(h, (octet*)h, ec->f, stack);
	// шаг 8: если h = 0, то h <- 1
	if (qrIsZero(h, ec->f))
		qrSetUnity(h, ec->f);
	// шаг 9: выделить части подписи
	wwFrom(r, sig, order_no);
	wwFrom(s, sig + ld / 16, order_no);
	for (i = order_no; i < ld / 16; ++i)
		if (sig[i] || sig[i + ld / 16])
		{
			_dstuCloseEc(ec);
			return ERR_BAD_SIG;
		}
	// шаги 10, 11: проверить r и s
	if (wwIsZero(r, order_n) ||
		wwIsZero(s, order_n) ||
		wwCmp(r, ec->order, order_n) >= 0 ||
		wwCmp(s, ec->order, order_n) >= 0)
	{
		_dstuCloseEc(ec);
		return ERR_BAD_SIG;
	}
	// шаг 12: R <- sP + rQ
	if (!ecAddMulA(x, ec, stack, 2, ec->base, s, order_n, x, r, order_n))
	{
		_dstuCloseEc(ec);
		return ERR_BAD_SIG;
	}
	// шаг 13: y <- h * x
	qrMul(y, x, h, ec->f, stack);
	// шаг 14: r' <- \bar{y}
	ASSERT(order_n <= ec->f->n);
	qrTo((octet*)s, y, ec->f, stack);
	wwFrom(s, s, order_no);
	wwTrimHi(s, order_n, order_nb - 1);
	// шаг 15:
	if (!wwEq(r, s, order_n))
		code = ERR_BAD_SIG;
	// все нормально
	_dstuCloseEc(ec);
	return code;
}