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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }