static err_t fileMsgRead(size_t* read, void* buf, size_t count, void* file) { file_msg_st* f; // pre ASSERT(memIsValid(file, sizeof(file_msg_st))); ASSERT(memIsValid(buf, count)); ASSERT(memIsValid(read, sizeof(size_t))); // найти сообщение f = (file_msg_st*)file; if (f->i >= 4) return ERR_FILE_READ; if (!_msgs[f->i].valid) return ERR_FILE_NOT_FOUND; // прочитать частично? ASSERT(f->offset <= _msgs[f->i].len); if (count + f->offset > _msgs[f->i].len) { memCopy(buf, _msgs[f->i].buf + f->offset, *read = _msgs[f->i].len - f->offset); ++f->i, f->offset = 0; return ERR_MAX; } // прочитать полностью memCopy(buf, _msgs[f->i].buf + f->offset, *read = count); f->offset += count; // конец сообщения? if (f->offset == _msgs[f->i].len) ++f->i, f->offset = 0; // все нормально return ERR_OK; }
static err_t fileCreate(void* file, void* data, size_t data_len) { file_st* f = (file_st*)file; u16 len; // pre if (!memIsValid(f, sizeof(file_st)) || !memIsValid(data, data_len)) return ERR_BAD_INPUT; // запомнить буфер f->data = data; f->data_len = data_len; // нет пакетов? if (data_len < 2) { f->frame = 0; f->frame_len = f->frame_offset = 0; } // найти первый пакет else { u16From(&len, data, 2); f->frame_len = (size_t)len; f->frame = f->data + 2; f->frame_offset = 0; // выход за границы? if (f->frame + f->frame_len > f->data + f->data_len) return ERR_BAD_FORMAT; } // все нормально return ERR_OK; }
static err_t bakeTestCertVal(octet* pubkey, const bign_params* params, const octet* data, size_t len) { if (!memIsValid(params, sizeof(bign_params)) || (params->l != 128 && params->l != 192 && params->l != 256) || !memIsNullOrValid(pubkey, params->l / 2)) return ERR_BAD_INPUT; if (!memIsValid(data, len) || len < params->l / 2) return ERR_BAD_CERT; if (pubkey) memCopy(pubkey, data + (len - params->l / 2), params->l / 2); 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; }
static err_t fileRead(size_t* read, void* buf, size_t count, void* file) { file_st* f = (file_st*)file; u16 len; err_t code; // pre ASSERT(memIsValid(f, sizeof(file_st))); ASSERT(memIsValid(buf, count)); ASSERT(memIsValid(read, sizeof(size_t))); // достигнут конец файла? if (f->frame == 0) { *read = 0; return ERR_MAX; } // достигается конец файла? if (f->frame_offset + count > f->frame_len) { *read = f->frame_len - f->frame_offset; memCopy(buf, f->frame + f->frame_offset, *read); code = ERR_MAX; } // обычное чтение else { *read = count; memCopy(buf, f->frame + f->frame_offset, *read); code = ERR_OK; } // к следующему пакету f->frame += f->frame_len; if (f->frame + 2 >= f->data + f->data_len) { f->frame = 0; f->frame_len = f->frame_offset = 0; } else { u16From(&len, f->frame, 2); f->frame_len = (size_t)len; f->frame += 2; f->frame_offset = 0; // выход за границы? if (f->frame + f->frame_len > f->data + f->data_len) return ERR_BAD_FORMAT; } // все нормально return code; }
void strCopy(char* dest, const char* src) { ASSERT(strIsValid(src)); ASSERT(memIsValid(dest, strLen(src) + 1)); ASSERT(memIsDisjoint(src, dest, strLen(src) + 1)); memcpy(dest, src, strLen(src) + 1); }
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; }
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 dstuStdParams(dstu_params* params, const char* name) { if (!memIsValid(params, sizeof(dstu_params))) return ERR_BAD_INPUT; memSetZero(params, sizeof(dstu_params)); if (strEq(name, _curve163pb_name)) { _LOAD_NAMED_PARAMS(params, curve163pb); memCopy(params->P, _curve163pb_P, sizeof(_curve163pb_P)); return ERR_OK; } if (strEq(name, _curve167pb_name)) { _LOAD_NAMED_PARAMS(params, curve167pb); return ERR_OK; } if (strEq(name, _curve173pb_name)) { _LOAD_NAMED_PARAMS(params, curve173pb); return ERR_OK; } if (strEq(name, _curve179pb_name)) { _LOAD_NAMED_PARAMS(params, curve179pb); return ERR_OK; } if (strEq(name, _curve191pb_name)) { _LOAD_NAMED_PARAMS(params, curve191pb); return ERR_OK; } if (strEq(name, _curve233pb_name)) { _LOAD_NAMED_PARAMS(params, curve233pb); return ERR_OK; } if (strEq(name, _curve257pb_name)) { _LOAD_NAMED_PARAMS(params, curve257pb); return ERR_OK; } if (strEq(name, _curve307pb_name)) { _LOAD_NAMED_PARAMS(params, curve307pb); return ERR_OK; } if (strEq(name, _curve367pb_name)) { _LOAD_NAMED_PARAMS(params, curve367pb); return ERR_OK; } if (strEq(name, _curve431pb_name)) { _LOAD_NAMED_PARAMS(params, curve431pb); return ERR_OK; } return ERR_FILE_NOT_FOUND; }
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; }
static err_t fileWrite(size_t* written, const void* buf, size_t count, void* file) { file_st* f = (file_st*)file; u16 len; // pre ASSERT(memIsValid(f, sizeof(file_st))); ASSERT(memIsValid(buf, count)); ASSERT(memIsValid(written, sizeof(size_t))); // конец файла? // запись не с начала пакета? // отличаются длины пакета и сообщения? // отличается содержимое? if (f->frame == 0 || f->frame_offset != 0 || f->frame_len != count || !memEq(f->frame, buf, count)) return ERR_FILE_WRITE; // к следующему пакету f->frame += f->frame_len; if (f->frame + 2 >= f->data + f->data_len) { f->frame = 0; f->frame_len = f->frame_offset = 0; } else { u16From(&len, f->frame, 2); f->frame_len = (size_t)len; f->frame += 2; f->frame_offset = 0; // выход за границы? if (f->frame + f->frame_len > f->data + f->data_len) return ERR_BAD_FORMAT; } // все нормально *written = count; return ERR_OK; }
static err_t fileMsgWrite(size_t* written, const void* buf, size_t count, void* file) { file_msg_st* f; // pre ASSERT(memIsValid(file, sizeof(file_msg_st))); ASSERT(memIsValid(buf, count)); ASSERT(memIsValid(written, sizeof(size_t))); // найти сообщение f = (file_msg_st*)file; if (f->i >= 4) return ERR_FILE_WRITE; // записать if (count > sizeof(_msgs[f->i].buf)) return ERR_OUTOFMEMORY; _msgs[f->i].valid = TRUE; memCopy(_msgs[f->i].buf, buf, count); *written = _msgs[f->i].len = count; // к следующему сообщению ++f->i, f->offset = 0; // все нормально return ERR_OK; }
err_t g12sStdParams(g12s_params* params, const char* name) { if (!memIsValid(params, sizeof(g12s_params))) return ERR_BAD_INPUT; memSetZero(params, sizeof(g12s_params)); if (strEq(name, _a1_name)) { _LOAD_NAMED_PARAMS(params, a1); return ERR_OK; } if (strEq(name, _cryptoproA_name)) { _LOAD_NAMED_PARAMS(params, cryptoproA); return ERR_OK; } if (strEq(name, _cryptoproB_name)) { _LOAD_NAMED_PARAMS(params, cryptoproB); return ERR_OK; } if (strEq(name, _cryptoproC_name)) { _LOAD_NAMED_PARAMS(params, cryptoproC); return ERR_OK; } if (strEq(name, _cryptocom_name)) { _LOAD_NAMED_PARAMS(params, cryptocom); return ERR_OK; } if (strEq(name, _a2_name)) { _LOAD_NAMED_PARAMS(params, a2); return ERR_OK; } if (strEq(name, _paramsetA512_name)) { _LOAD_NAMED_PARAMS(params, paramsetA512); return ERR_OK; } if (strEq(name, _paramsetB512_name)) { _LOAD_NAMED_PARAMS(params, paramsetB512); return ERR_OK; } return ERR_FILE_NOT_FOUND; }
static err_t _dstuCreateEc( ec_o** pec, /* [out] описание эллиптической кривой */ const dstu_params* params, /* [in] долговременные параметры */ _dstu_deep_i deep /* [in] потребности в стековой памяти */ ) { // размерности size_t m; size_t n; size_t f_keep; size_t f_deep; size_t ec_d; size_t ec_keep; size_t ec_deep; // состояние void* state; size_t* p; /* описание многочлена */ qr_o* f; /* поле */ octet* A; /* коэффициент A */ ec_o* ec; /* кривая */ void* stack; // pre ASSERT(memIsValid(pec, sizeof(*pec))); // минимальная проверка входных данных if (!memIsValid(params, sizeof(dstu_params)) || (m = params->p[0]) < 160 || m > 509 || params->A > 1) return ERR_BAD_PARAMS; // определить размерности n = W_OF_B(m); f_keep = gf2Create_keep(m); f_deep = gf2Create_deep(m); ec_d = 3; ec_keep = ec2CreateLD_keep(n); ec_deep = ec2CreateLD_deep(n, f_deep); // создать состояние state = blobCreate( f_keep + ec_keep + utilMax(4, 4 * sizeof(size_t) + f_deep, O_OF_B(m) + ec_deep, ecCreateGroup_deep(f_deep), deep(n, f_deep, ec_d, ec_deep))); if (state == 0) return ERR_NOT_ENOUGH_MEMORY; // создать поле f = (qr_o*)((octet*)state + ec_keep); p = (size_t*)((octet*)f + f_keep); p[0] = params->p[0]; p[1] = params->p[1]; p[2] = params->p[2]; p[3] = params->p[3]; stack = p + 4; if (!gf2Create(f, p, stack)) { blobClose(state); return ERR_BAD_PARAMS; } // создать кривую и группу ec = (ec_o*)state; A = (octet*)p; A[0] = params->A; memSetZero(A + 1, f->no - 1); stack = A + f->no; if (!ec2CreateLD(ec, f, A, params->B, stack) || !ecCreateGroup(ec, params->P, params->P + ec->f->no, params->n, ec->f->no, params->c, stack)) { blobClose(state); return ERR_BAD_PARAMS; } // присоединить f к ec objAppend(ec, f, 0); // все нормально *pec = ec; return ERR_OK; }
static err_t g12sCreateEc( ec_o** pec, /* [out] описание эллиптической кривой */ const g12s_params* params, /* [in] долговременные параметры */ g12s_deep_i deep /* [in] потребности в стековой памяти */ ) { // размерности size_t n, no, nb; size_t f_keep; size_t f_deep; size_t ec_d; size_t ec_keep; size_t ec_deep; // состояние void* state; qr_o* f; /* базовое поле */ ec_o* ec; /* кривая */ void* stack; // pre ASSERT(memIsValid(pec, sizeof(*pec))); // минимальная проверка входных данных if (!memIsValid(params, sizeof(g12s_params)) || params->l != 256 && params->l != 512) return ERR_BAD_PARAMS; // определить размерности no = memNonZeroSize(params->p, sizeof(params->p) * params->l / 512); n = W_OF_O(no); f_keep = gfpCreate_keep(no); f_deep = gfpCreate_deep(no); ec_d = 3; ec_keep = ecpCreateJ_keep(no); ec_deep = ecpCreateJ_deep(no, f_deep); // создать состояние state = blobCreate( f_keep + ec_keep + utilMax(3, ec_deep, ecCreateGroup_deep(f_deep), deep(n, f_deep, ec_d, ec_deep))); if (state == 0) return ERR_NOT_ENOUGH_MEMORY; // создать поле f = (qr_o*)((octet*)state + ec_keep); stack = (octet*)f + f_keep; if (!gfpCreate(f, params->p, no, stack)) { blobClose(state); return ERR_BAD_PARAMS; } // проверить длину p nb = wwBitSize(f->mod, n); if (params->l == 256 && nb <= 253 || params->l == 512 && nb <= 507) { blobClose(state); return ERR_BAD_PARAMS; } // создать кривую и группу ec = (ec_o*)state; if (!ecpCreateJ(ec, f, params->a, params->b, stack) || !ecCreateGroup(ec, params->xP, params->yP, params->q, params->l / 8, params->n, stack)) { blobClose(state); return ERR_BAD_PARAMS; } // проверить q n = W_OF_B(params->l); nb = wwBitSize(ec->order, n); if (params->l == 256 && nb <= 254 || params->l == 512 && nb <= 508 || zzIsEven(ec->order, n)) { blobClose(state); return ERR_BAD_PARAMS; } // присоединить f к ec objAppend(ec, f, 0); // все нормально *pec = 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; }
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 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; }
bool_t strIsValid(const char* str) { return memIsValid(str, strLen(str) + (str ? 1 : 0)); }