diff --git a/AUTHORS.md b/AUTHORS.md index 834a1016..b54fd775 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -45,6 +45,7 @@ Contributors* - license issues - bign/params - code review + - memory alignment - Alexander Zhirkevich - cmd/sig, cmd/rng, cmd/test - Vladimir Komisarenko diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b083b54..0222c6c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,10 @@ cmake_minimum_required(VERSION 3.5...3.31) -project(BEE2 C) +project(BEE2 + VERSION 2.1.9 + LANGUAGES C +) -set(BEE2_VERSION_MAJOR "2") -set(BEE2_VERSION_MINOR "1") -set(BEE2_VERSION_PATCH "8") -set(BEE2_VERSION - "${BEE2_VERSION_MAJOR}.${BEE2_VERSION_MINOR}.${BEE2_VERSION_PATCH}") +include(GNUInstallDirs) # \remark Set BUILD_PIC even for static libraries if they are linked # into shared libraries @@ -115,17 +114,19 @@ if(CMAKE_COMPILER_IS_CLANG) -fno-strict-aliasing") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g3") set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -O0 -g3 -coverage") - set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -fsanitize=address \ - -fno-common -fsanitize=undefined -fno-sanitize-recover -O3 \ - -fno-strict-aliasing") - set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -fsanitize=address \ - -fno-common -fsanitize=undefined -fno-sanitize-recover -O1 -g3 \ - -fno-omit-frame-pointer -fno-optimize-sibling-calls") + set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -fsanitize=address,undefined\ + -fno-sanitize=signed-integer-overflow -fno-sanitize=unsigned-integer-overflow\ + -fno-sanitize-recover\ + -fno-common -O3 -fno-strict-aliasing") + set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -fsanitize=address,udefined \ + -fno-sanitize=signed-integer-overflow -fno-sanitize=unsigned-integer-overflow\ + -fno-sanitize-recover\ + -fno-common -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls") set(CMAKE_C_FLAGS_MEMSAN "${CMAKE_C_FLAGS_MEMSAN} -fsanitize=memory -O3 \ -fno-strict-aliasing") set(CMAKE_C_FLAGS_MEMSANDBG "${CMAKE_C_FLAGS_MEMSANDBG} -fsanitize=memory \ - -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls \ - -fsanitize-memory-track-origins=2") + -fsanitize-memory-track-origins=2\ + -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls") set(CMAKE_C_FLAGS_CHECK "${CMAKE_C_FLAGS_CHECK} -Werror -O1 -Wcast-qual") endif(CMAKE_COMPILER_IS_CLANG) @@ -145,14 +146,6 @@ if(BUILD_FAST) add_definitions(-DSAFE_FAST) endif() -if(NOT LIB_INSTALL_DIR) - set(LIB_INSTALL_DIR lib) -endif() - -if(NOT BIN_INSTALL_DIR) - set(BIN_INSTALL_DIR bin) -endif() - include_directories(include) include_directories(src) diff --git a/README.md b/README.md index 335f6525..d41993c5 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ Russia and Ukraine. mkdir build cd build cmake [-DCMAKE_BUILD_TYPE={Release|Debug|Coverage|ASan|ASanDbg|MemSan|MemSanDbg|Check}]\ - [-DBUILD_FAST=ON]\ [-DBASH_PLATFORM={BASH_32|BASH_64|BASH_AVX2|BASH_AVX512|BASH_NEON}]\ .. make @@ -53,7 +52,6 @@ compiler: > mkdir build > cd build > cmake [-DCMAKE_BUILD_TYPE={Release|Debug|Coverage|ASan|ASanDbg|MemSan|MemSanDbg|Check}]\ -> [-DBUILD_FAST=ON]\ > [-DBASH_PLATFORM={BASH_32|BASH_64|BASH_AVX2|BASH_AVX512|BASH_NEON}]\ > -G "MinGW Makefiles"\ > .. @@ -69,9 +67,6 @@ Build types (`Release` by default): * `MemSan`, `MemSanDbg` — [memory sanitizer](http://code.google.com/p/memory-sanitizer/); * `Check` — strict compile rules. -The `BUILD_FAST` option (`OFF` by default) switches from safe (constant-time) -functions to fast (non-constant-time) ones. - The `BASH_PLATFORM` option (`BASH_64` by default) requests to use a specific implementation of the STB 34.101.77 algorithms optimized for a given hardware platform. The request may be rejected if it conflicts with other options. diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt index 85213db5..a84e779a 100644 --- a/cmd/CMakeLists.txt +++ b/cmd/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable(bee2cmd cvc/cvc.c cvr/cvr.c es/es.c + fmt/fmt.c kg/kg.c pwd/pwd.c sig/sig.c @@ -33,7 +34,7 @@ include_directories(include) target_link_libraries(bee2cmd bee2_static) install(TARGETS bee2cmd - DESTINATION ${BIN_INSTALL_DIR} + DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) diff --git a/cmd/cmd_main.c b/cmd/cmd_main.c index 41ea3b2d..48cc7abb 100644 --- a/cmd/cmd_main.c +++ b/cmd/cmd_main.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: main \project bee2/cmd \created 2022.06.07 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -93,6 +93,7 @@ extern err_t cvcInit(); extern err_t cvrInit(); extern err_t sigInit(); extern err_t csrInit(); +extern err_t fmtInit(); extern err_t stampInit(); extern err_t esInit(); extern err_t stInit(); @@ -117,6 +118,8 @@ static err_t cmdInit() ERR_CALL_CHECK(code); code = csrInit(); ERR_CALL_CHECK(code); + code = fmtInit(); + ERR_CALL_CHECK(code); code = stampInit(); ERR_CALL_CHECK(code); code = esInit(); @@ -200,7 +203,7 @@ int main(int argc, char* argv[]) // обработка команды for (pos = 0; pos < _count; ++pos) if (strEq(argv[1], _cmds[pos].name)) - return _cmds[pos].fn(argc - 1, argv + 1); + return _cmds[pos].fn(argc - 1, argv + 1); printf("bee2cmd: %s\n", errMsg(ERR_CMD_NOT_FOUND)); return -1; } diff --git a/cmd/core/cmd_arg.c b/cmd/core/cmd_arg.c index 9b75d974..e4529831 100644 --- a/cmd/core/cmd_arg.c +++ b/cmd/core/cmd_arg.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: parsing arguments \project bee2/cmd \created 2022.06.08 -\version 2025.06.10 +\version 2025.09.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -127,10 +127,13 @@ err_t cmdArgCreate(int* argc, char*** argv, const char* args) *argc += 1, count += c, size += s; } // выделить и разметить память - if (!(state = blobCreate(*argc * sizeof(char*) + size))) + state = blobCreate2( + (size_t)*argc * sizeof(char*), + size, + SIZE_MAX, + argv, &strs); + if (state == 0) return ERR_OUTOFMEMORY; - *argv = (char**)state; - strs = (char*)(*argv + *argc); // разобрать аргументы for (size = 0, pos = 0, count = argWsDec(args); args[count] != '\0';) { diff --git a/cmd/core/cmd_cvc.c b/cmd/core/cmd_cvc.c index cd59a8c6..5de25dcf 100644 --- a/cmd/core/cmd_cvc.c +++ b/cmd/core/cmd_cvc.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: managing CV-certificates \project bee2/cmd \created 2022.08.20 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -227,14 +227,16 @@ err_t cmdCVCsFind(size_t* offset, const octet* certs, size_t certs_len, err_t cmdCVCsCheck(const octet* certs, size_t certs_len) { err_t code; - void* stack; - btok_cvc_t* cvc; + void* state; + btok_cvc_t* cvc; /* [1] */ // pre ASSERT(memIsValid(certs, certs_len)); // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(btok_cvc_t)); + code = cmdBlobCreate2(state, + sizeof(btok_cvc_t), + SIZE_MAX, + &cvc); ERR_CALL_CHECK(code); - cvc = (btok_cvc_t*)stack; // цикл по сертификатам while (certs_len) { @@ -244,22 +246,22 @@ err_t cmdCVCsCheck(const octet* certs, size_t certs_len) code = ERR_BAD_CERTRING; else code = btokCVCUnwrap(cvc, certs, len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // к следующему certs += len, certs_len -= len; } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } err_t cmdCVCsVal(const octet* certs, size_t certs_len, const octet date[6]) { err_t code; - void* stack; size_t len; - btok_cvc_t* cvca; - btok_cvc_t* cvc; + void* state; + btok_cvc_t* cvca; /* [1] */ + btok_cvc_t* cvc; /* [1] */ // pre ASSERT(memIsValid(certs, certs_len)); ASSERT(memIsNullOrValid(date, 6)); @@ -267,17 +269,19 @@ err_t cmdCVCsVal(const octet* certs, size_t certs_len, const octet date[6]) if (!certs_len) return ERR_OK; // выделить и разметить память - code = cmdBlobCreate(stack, 2 * sizeof(btok_cvc_t)); + code = cmdBlobCreate2(state, + sizeof(btok_cvc_t), + sizeof(btok_cvc_t), + SIZE_MAX, + &cvca, &cvc); ERR_CALL_CHECK(code); - cvca = (btok_cvc_t*)stack; - cvc = cvca + 1; // найти и разобрать первый сертификат len = btokCVCLen(certs, certs_len); if (len == SIZE_MAX) code = ERR_BAD_CERT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = btokCVCUnwrap(cvca, certs, len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); certs_len -= len, certs += len; // цикл по остальным сертификатам while (certs_len) @@ -286,34 +290,36 @@ err_t cmdCVCsVal(const octet* certs, size_t certs_len, const octet date[6]) len = btokCVCLen(certs, certs_len); if (len == SIZE_MAX) code = ERR_BAD_CERT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить сертификат if (len == certs_len && date && !memIsZero(date, 6)) code = btokCVCVal2(cvc, certs, len, cvca, date); else code = btokCVCVal2(cvc, certs, len, cvca, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // к следующему сертификату certs_len -= len, certs += len; // издатель <- эмитент memCopy(cvca, cvc, sizeof(btok_cvc_t)); } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } err_t cmdCVCsPrint(const octet* certs, size_t certs_len) { err_t code; - void* stack; - btok_cvc_t* cvc; + void* state; + btok_cvc_t* cvc; /* [1] */ // pre ASSERT(memIsValid(certs, certs_len)); // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(btok_cvc_t)); + code = cmdBlobCreate2(state, + sizeof(btok_cvc_t), + SIZE_MAX, + &cvc); ERR_CALL_CHECK(code); - cvc = (btok_cvc_t*)stack; // цикл по сертификатам while (certs_len) { @@ -323,20 +329,20 @@ err_t cmdCVCsPrint(const octet* certs, size_t certs_len) code = ERR_BAD_CERTRING; else code = btokCVCUnwrap(cvc, certs, len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // печатать printf(" %s (%u bits, issued by %s, ", cvc->holder, (unsigned)cvc->pubkey_len * 2, cvc->authority); code = cmdPrintDate(cvc->from); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); printf("-"); code = cmdPrintDate(cvc->until); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); printf(")\n"); // к следующему certs += len, certs_len -= len; } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_privkey.c b/cmd/core/cmd_privkey.c index 63377098..26a33708 100644 --- a/cmd/core/cmd_privkey.c +++ b/cmd/core/cmd_privkey.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: managing private keys \project bee2/cmd \created 2022.06.20 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -29,10 +29,10 @@ err_t cmdPrivkeyWrite(const octet privkey[], size_t privkey_len, { err_t code; const size_t iter = 10000; - void* stack; - octet* salt; - octet* epki; size_t epki_len; + void* state; + octet* salt; /* [8] */ + octet* epki; /* [epki_len] */ // pre ASSERT(privkey_len == 24 || privkey_len == 32 || privkey_len == 48 || privkey_len == 64); @@ -42,23 +42,25 @@ err_t cmdPrivkeyWrite(const octet privkey[], size_t privkey_len, // определить длину контейнера code = bpkiPrivkeyWrap(0, &epki_len, 0, privkey_len, 0, 0, 0, iter); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, 8 + epki_len); + // выделить и разметить память + code = cmdBlobCreate2(state, + 8, + epki_len, + SIZE_MAX, + &salt, &epki); ERR_CALL_CHECK(code); - salt = (octet*)stack; - epki = salt + 8; // запустить ГСЧ code = cmdRngStart(TRUE); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // установить защиту rngStepR(salt, 8, 0); code = bpkiPrivkeyWrap(epki, 0, privkey, privkey_len, (const octet*)pwd, cmdPwdLen(pwd), salt, iter); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать в файл code = cmdFileWrite(name, epki, epki_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -76,12 +78,12 @@ err_t cmdPrivkeyRead(octet privkey[], size_t* privkey_len, const char* name, size_t epki_len; size_t epki_len_min; size_t epki_len_max; - void* stack; - octet* epki; + void* state; + octet* epki; /* [epki_len_max + 1] */ // pre ASSERT(memIsNullOrValid(privkey_len, sizeof(size_t))); ASSERT(!privkey_len || *privkey_len == 0 || *privkey_len == 24 || - *privkey_len == 32 || *privkey_len == 48 || *privkey_len == 64); + *privkey_len == 32 || *privkey_len == 48 || *privkey_len == 64); ASSERT(strIsValid(name)); ASSERT(cmdPwdIsValid(pwd)); // определить длину личного ключа по размеру контейнера @@ -119,25 +121,27 @@ err_t cmdPrivkeyRead(octet privkey[], size_t* privkey_len, const char* name, return ERR_OK; ASSERT(len == 24 || len == 32 || len == 48 || len == 64); ASSERT(memIsValid(privkey, len)); - // выделить память и разметить ее - code = cmdBlobCreate(stack, epki_len_max + 1); + // выделить и разметить память + code = cmdBlobCreate2(state, + epki_len_max + 1, + SIZE_MAX, + &epki); ERR_CALL_CHECK(code); - epki = (octet*)stack; // определить длину контейнера code = cmdFileReadAll(0, &epki_len, name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить длину code = (epki_len_min <= epki_len && epki_len <= epki_len_max) ? ERR_OK : ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // читать code = cmdFileReadAll(epki, &epki_len, name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // снять защиту code = bpkiPrivkeyUnwrap(privkey, &epki_len_min, epki, epki_len, (const octet*)pwd, cmdPwdLen(pwd)); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(epki_len_min == len); - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_pwd.c b/cmd/core/cmd_pwd.c index 14affacb..72bad309 100644 --- a/cmd/core/cmd_pwd.c +++ b/cmd/core/cmd_pwd.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: password management \project bee2/cmd \created 2022.06.13 -\version 2025.06.09 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -116,12 +116,12 @@ static err_t cmdPwdGenShare_internal(cmd_pwd_t* pwd, size_t scount, err_t code; const size_t iter = 10000; size_t epki_len; - void* stack; - octet* pwd_bin; - octet* state; - octet* share; - octet* salt; - octet* epki; + void* state; + octet* pwd_bin; /* [len] */ + octet* share; /* [scount * (len + 1)] */ + octet* mac_state; /* [beltMAC_keep()] (|share) */ + octet* salt; /* [8] */ + octet* epki; /* [epki_len] */ // pre ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t))); ASSERT(cmdPwdIsValid(spwd)); @@ -140,29 +140,29 @@ static err_t cmdPwdGenShare_internal(cmd_pwd_t* pwd, size_t scount, // запустить ГСЧ code = cmdRngStart(TRUE); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, len + - utilMax(2, - beltMAC_keep(), - scount * (len + 1) + epki_len + 8)); + // выделить и разметить память + code = cmdBlobCreate2(state, + len, + scount * (len + 1), + beltMAC_keep() | SIZE_HI, + (size_t)8, + epki_len, + SIZE_MAX, + &pwd_bin, &share, &mac_state, &salt, &epki); ERR_CALL_CHECK(code); - pwd_bin = (octet*)stack; - state = share = pwd_bin + len; - salt = share + scount * (len + 1); - epki = salt + 8; // генерировать пароль if (crc) { rngStepR(pwd_bin, len - 8, 0); - beltMACStart(state, pwd_bin, len - 8); - beltMACStepA(pwd_bin, len - 8, state); - beltMACStepG(pwd_bin + len - 8, state); + beltMACStart(mac_state, pwd_bin, len - 8); + beltMACStepA(pwd_bin, len - 8, mac_state); + beltMACStepG(pwd_bin + len - 8, mac_state); } else rngStepR(pwd_bin, len, 0); // разделить пароль на частичные секреты code = belsShare2(share, scount, threshold, len, pwd_bin, rngStepR, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // обновить ключ ГСЧ rngRekey(); // защитить частичные секреты @@ -172,17 +172,17 @@ static err_t cmdPwdGenShare_internal(cmd_pwd_t* pwd, size_t scount, rngStepR(salt, 8, 0); code = bpkiShareWrap(epki, 0, share, len + 1, (const octet*)spwd, cmdPwdLen(spwd), salt, iter); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать в файл code = cmdFileWrite(*shares, epki, epki_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); } // создать выходной (текстовый) пароль *pwd = cmdPwdCreate(2 * len); code = *pwd ? ERR_OK : ERR_OUTOFMEMORY; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); hexFrom(*pwd, pwd_bin, len); - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -193,11 +193,11 @@ static err_t cmdPwdReadShare_internal(cmd_pwd_t* pwd, size_t scount, size_t epki_len; size_t epki_len_min; size_t epki_len_max; - void* stack; - octet* share; - octet* state; - octet* epki; - octet* pwd_bin; + void* state; + octet* share; /* [scount * (len + 1)] */ + octet* mac_state; /* [beltMAC_keep()] */ + octet* epki; /* [epki_len_max + 1] */ + octet* pwd_bin; /* [len] */ size_t pos; // pre ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t))); @@ -234,51 +234,54 @@ static err_t cmdPwdReadShare_internal(cmd_pwd_t* pwd, size_t scount, code = bpkiShareWrap(0, &epki_len_max, 0, len + 1, 0, 0, 0, SIZE_MAX); ERR_CALL_CHECK(code); } - // выделить память и разметить ее - code = cmdBlobCreate(stack, scount * (len + 1) + epki_len_max + 1 + len); + // выделить и разметить память + code = cmdBlobCreate2(state, + scount * (len + 1), + beltMAC_keep() | SIZE_HI, + epki_len_max + 1, + len, + SIZE_MAX, + &share, &mac_state, &epki, &pwd_bin); ERR_CALL_HANDLE(code, cmdPwdClose(*pwd)); - share = state = (octet*)stack; - epki = share + scount * (len + 1); - pwd_bin = epki + epki_len_max + 1; // прочитать частичные секреты for (pos = 0; pos < scount; ++pos, ++shares) { size_t share_len; // определить длину контейнера code = cmdFileReadAll(0, &epki_len, *shares); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить длину code = (epki_len_min <= epki_len && epki_len <= epki_len_max) ? ERR_OK : ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // читать code = cmdFileReadAll(epki, &epki_len, *shares); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // декодировать code = bpkiShareUnwrap(share + pos * (len + 1), &share_len, epki, epki_len, (const octet*)spwd, cmdPwdLen(spwd)); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = (share_len == len + 1) ? ERR_OK : ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); } // собрать пароль code = belsRecover2(pwd_bin, scount, len, share); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить пароль if (crc) { - beltMACStart(state, pwd_bin, len - 8); - beltMACStepA(pwd_bin, len - 8, state); - if (!beltMACStepV(pwd_bin + len - 8, state)) + beltMACStart(mac_state, pwd_bin, len - 8); + beltMACStepA(pwd_bin, len - 8, mac_state); + if (!beltMACStepV(pwd_bin + len - 8, mac_state)) code = ERR_BAD_CRC; } - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // создать выходной (текстовый) пароль *pwd = cmdPwdCreate(2 * len); code = *pwd ? ERR_OK : ERR_OUTOFMEMORY; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); hexFrom(*pwd, pwd_bin, len); - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_rng.c b/cmd/core/cmd_rng.c index 29f2743a..7ae62d2b 100644 --- a/cmd/core/cmd_rng.c +++ b/cmd/core/cmd_rng.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: random number generation \project bee2/cmd \created 2022.06.08 -\version 2025.06.11 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -161,30 +161,33 @@ err_t cmdRngStart(bool_t verbose) // нет, подключить клавиатурный источник else if (code == ERR_NOT_ENOUGH_ENTROPY) { - void* stack; - tm_ticks_t* data; - octet* hash; void* state; + tm_ticks_t* data; /* [128] */ + octet* hash; /* [32] (|data) */ + void* hash_state; /* [beltHash_keep()] */ + void* prng_state; /* [prngEcho_keep()] (|hash_state) */ // выделить и разметить память - code = cmdBlobCreate(stack, 128 * sizeof(tm_ticks_t) + - MAX2(beltHash_keep(), prngEcho_keep())); + code = cmdBlobCreate2(state, + 128 * sizeof(tm_ticks_t), + 32 | SIZE_HI, + beltHash_keep(), + prngEcho_keep() | SIZE_HI, + SIZE_MAX, + &data, &hash, &hash_state, &prng_state); ERR_CALL_CHECK(code); - data = (tm_ticks_t*)stack; - hash = (octet*)data; - state = data + 128; // собрать данные от клавиатурного источника code = cmdRngKbRead(data); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // хэшировать - beltHashStart(state); - beltHashStepH(data, 128 * sizeof(tm_ticks_t), state); - beltHashStepG(hash, state); + beltHashStart(hash_state); + beltHashStepH(data, 128 * sizeof(tm_ticks_t), hash_state); + beltHashStepG(hash, hash_state); // запустить echo-генератор - prngEchoStart(state, hash, 32); + prngEchoStart(prng_state, hash, 32); // запустить генератор - code = rngCreate(prngEchoRead, state); + code = rngCreate(prngEchoRead, prng_state); // освободить память - cmdBlobClose(stack); + cmdBlobClose(state); } if (verbose) printf("%s\n", errMsg(code)); diff --git a/cmd/core/cmd_sig.c b/cmd/core/cmd_sig.c index fa4483c7..9e8821bf 100644 --- a/cmd/core/cmd_sig.c +++ b/cmd/core/cmd_sig.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: signing files \project bee2/cmd \created 2022.08.20 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -233,9 +233,9 @@ static err_t cmdSigHash(octet hash[], size_t hash_len, const char* name, { const size_t buf_size = 4096; err_t code; - octet* stack; - octet* buf; - void* state; + octet* state; + octet* buf; /* [buf_size] */ + void* hash_state; /* [beltHash_keep() || bashHash_keep()] */ file_t file; size_t size; // pre @@ -244,56 +244,57 @@ static err_t cmdSigHash(octet hash[], size_t hash_len, const char* name, ASSERT(memIsValid(hash, hash_len)); ASSERT(strIsValid(name)); // выделить и разметить память - code = cmdBlobCreate(stack, buf_size + - (hash_len <= 32 ? beltHash_keep() : bashHash_keep())); + code = cmdBlobCreate2(state, + buf_size, + (hash_len <= 32 ? beltHash_keep() : bashHash_keep()), + SIZE_MAX, + &buf, &hash_state); ERR_CALL_CHECK(code); - buf = (octet*)stack; - state = buf + buf_size; // начать хэширование if (hash_len <= 32) - beltHashStart(state); + beltHashStart(hash_state); else - bashHashStart(state, hash_len * 4); + bashHashStart(hash_state, hash_len * 4); // открыть файл code = cmdFileOpen(file, name, "rb"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить размер файла size = fileSize(file); if (size == SIZE_MAX) code = ERR_FILE_READ; else if (size < drop) code = ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); // хэшировать файл for (size -= drop; size;) { size_t count = MIN2(size, buf_size); if (fileRead2(buf, count, file) != count) code = ERR_FILE_READ; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); if (hash_len <= 32) - beltHashStepH(stack, count, state); + beltHashStepH(state, count, hash_state); else - bashHashStepH(stack, count, state); + bashHashStepH(state, count, hash_state); size -= count; } code = cmdFileClose2(file); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // хэшировать сертификаты и дату if (hash_len <= 32) { - beltHashStepH(certs, certs_len, state); - beltHashStepH(date, 6, state); - beltHashStepG2(hash, hash_len, state); + beltHashStepH(certs, certs_len, hash_state); + beltHashStepH(date, 6, hash_state); + beltHashStepG2(hash, hash_len, hash_state); } else { - bashHashStepH(certs, certs_len, state); - bashHashStepH(date, 6, state); - bashHashStepG(hash, hash_len, state); + bashHashStepH(certs, certs_len, hash_state); + bashHashStepH(date, 6, hash_state); + bashHashStepG(hash, hash_len, hash_state); } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -329,13 +330,13 @@ err_t cmdSigSign(const char* sig_name, const char* name, const char* certs, const octet date[6], const octet privkey[], size_t privkey_len) { err_t code; - void* stack; - cmd_sig_t* sig; - bign_params* params; - octet* oid_der; size_t oid_len = 16; - octet* hash; - octet* t; + void* state; + cmd_sig_t* sig; /* [1] */ + bign_params* params; /* [1] */ + octet* oid_der; /* [oid_len] */ + octet* hash; /* [privkey_len] */ + octet* t; /* [privkey_len] */ size_t t_len; // входной контроль if (!strIsValid(sig_name) || !strIsValid(name) || @@ -347,14 +348,15 @@ err_t cmdSigSign(const char* sig_name, const char* name, const char* certs, if (!memIsZero(date, 6) && !tmDateIsValid2(date)) return ERR_BAD_DATE; // выделить и разметить память - code = cmdBlobCreate(stack, - sizeof(cmd_sig_t) + sizeof(bign_params) + oid_len + 2 * privkey_len); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + sizeof(bign_params), + oid_len, + privkey_len, + privkey_len, + SIZE_MAX, + &sig, ¶ms, &oid_der, &hash, &t); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; - params = (bign_params*)(sig + 1); - oid_der = (octet*)(params + 1); - hash = oid_der + 16; - t = hash + privkey_len; // зафиксировать дату memCopy(sig->date, date, 6); // указаны сертификаты? @@ -363,10 +365,10 @@ err_t cmdSigSign(const char* sig_name, const char* name, const char* certs, // собрать сертификаты sig->certs_len = sizeof(sig->certs); code = cmdCVCsCreate(sig->certs, &sig->certs_len, certs); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить цепочку code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); } else sig->certs_len = 0; @@ -377,30 +379,30 @@ err_t cmdSigSign(const char* sig_name, const char* name, const char* certs, size_t cert_len; // найти последний сертификат code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить соответствие личному ключу code = btokCVCMatch(sig->certs + offset, cert_len, privkey, privkey_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); } // загрузить долговременные параметры code = cmdSigParamsStd(params, privkey_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // хэшировать code = cmdSigHash(hash, privkey_len, name, 0, sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); if (privkey_len <= 32) { code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } else { code = bignOidToDER(oid_der, &oid_len, privkey_len == 48 ? "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } // получить случайные числа @@ -421,14 +423,14 @@ err_t cmdSigSign(const char* sig_name, const char* name, const char* certs, t, t_len); sig->sig_len = privkey_len / 2 * 3; } - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // сохранить подпись if (cmdFileAreSame(name, sig_name)) code = cmdSigAppend(sig_name, sig); else code = cmdSigWrite(sig_name, sig); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -442,13 +444,13 @@ err_t cmdSigVerify(const char* name, const char* sig_name, const octet pubkey[], size_t pubkey_len) { err_t code; - void* stack; - cmd_sig_t* sig; - btok_cvc_t* cvc; - bign_params* params; - octet* oid_der; size_t oid_len = 16; - octet* hash; + void* state; + cmd_sig_t* sig; /* [1] */ + btok_cvc_t* cvc; /* [1] */ + bign_params* params; /* [1] */ + octet* oid_der; /* [oid_len] */ + octet* hash; /* [pubkey_len / 2] */ size_t drop; // входной контроль if (!strIsValid(name) || !strIsValid(sig_name) || @@ -457,27 +459,28 @@ err_t cmdSigVerify(const char* name, const char* sig_name, !memIsValid(pubkey, pubkey_len)) return ERR_BAD_INPUT; // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) + - sizeof(bign_params) + oid_len + pubkey_len / 2); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + sizeof(btok_cvc_t), + sizeof(bign_params), + oid_len, + pubkey_len / 2, + SIZE_MAX, + &sig, &cvc, ¶ms, &oid_der, &hash); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; - cvc = (btok_cvc_t*)(sig + 1); - params = (bign_params*)(cvc + 1); - oid_der = (octet*)(params + 1); - hash = oid_der + oid_len; // читать подпись code = cmdSigRead(sig, &drop, sig_name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // подпись в отдельном файле? if (!cmdFileAreSame(name, sig_name)) { code = drop == cmdFileSize(sig_name) ? ERR_OK : ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); drop = 0; } // проверить сертификаты code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // есть сертификаты? if (sig->certs_len) { @@ -485,33 +488,33 @@ err_t cmdSigVerify(const char* name, const char* sig_name, size_t cert_len; // найти и разобрать последний сертификат code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить открытый ключ последнего сертификата if (pubkey_len != cvc->pubkey_len || !memEq(pubkey, cvc->pubkey, pubkey_len)) code = ERR_BAD_PUBKEY; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); } // загрузить долговременные параметры code = cmdSigParamsStd(params, pubkey_len / 2); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // хэшировать code = cmdSigHash(hash, pubkey_len / 2, name, drop, sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); if (pubkey_len <= 64) { code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } else { code = bignOidToDER(oid_der, &oid_len, pubkey_len == 96 ? "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } // проверить открытый ключ @@ -519,14 +522,14 @@ err_t cmdSigVerify(const char* name, const char* sig_name, code = bign96PubkeyVal(params, pubkey); else code = bignPubkeyVal(params, pubkey); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить подпись if (pubkey_len == 48) code = bign96Verify(params, oid_der, oid_len, hash, sig->sig, pubkey); else code = bignVerify(params, oid_der, oid_len, hash, sig->sig, pubkey); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -534,13 +537,13 @@ err_t cmdSigVerify2(const char* name, const char* sig_name, const octet anchor[], size_t anchor_len) { err_t code; - void* stack; - cmd_sig_t* sig; - btok_cvc_t* cvc; - bign_params* params; - octet* oid_der; size_t oid_len = 16; - octet* hash; + void* state; + cmd_sig_t* sig; /* [1] */ + btok_cvc_t* cvc; /* [1] */ + bign_params* params; /* [1] */ + octet* oid_der; /* [oid_len] */ + octet* hash; /* [64] */ size_t drop; size_t offset; size_t cert_len; @@ -549,54 +552,55 @@ err_t cmdSigVerify2(const char* name, const char* sig_name, !memIsValid(anchor, anchor_len)) return ERR_BAD_INPUT; // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) + - sizeof(bign_params) + oid_len + 64); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + sizeof(btok_cvc_t), + sizeof(bign_params), + oid_len, + (size_t)64, + SIZE_MAX, + &sig, &cvc, ¶ms, &oid_der, &hash); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; - cvc = (btok_cvc_t*)(sig + 1); - params = (bign_params*)(cvc + 1); - oid_der = (octet*)(params + 1); - hash = oid_der + oid_len; // читать подпись code = cmdSigRead(sig, &drop, sig_name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // подпись в отдельном файле? if (!cmdFileAreSame(name, sig_name)) { code = drop == cmdFileSize(sig_name) ? ERR_OK : ERR_BAD_FORMAT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); drop = 0; } // цепочка сертификатов включает anchor? code = cmdCVCsFind(0, sig->certs, sig->certs_len, anchor, anchor_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить цепочку code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // найти последний сертификат code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // разобрать последний сертификат code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // загрузить долговременные параметры code = cmdSigParamsStd(params, cvc->pubkey_len / 2); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // хэшировать code = cmdSigHash(hash, cvc->pubkey_len / 2, name, drop, sig->certs, sig->certs_len, sig->date); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); if (cvc->pubkey_len <= 64) { code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } else { code = bignOidToDER(oid_der, &oid_len, cvc->pubkey_len == 96 ? "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); ASSERT(oid_len == 11); } // проверить открытый ключ @@ -604,7 +608,7 @@ err_t cmdSigVerify2(const char* name, const char* sig_name, code = bign96PubkeyVal(params, cvc->pubkey); else code = bignPubkeyVal(params, cvc->pubkey); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить подпись if (cvc->pubkey_len == 48) code = bign96Verify(params, oid_der, oid_len, hash, sig->sig, @@ -613,7 +617,7 @@ err_t cmdSigVerify2(const char* name, const char* sig_name, code = bignVerify(params, oid_der, oid_len, hash, sig->sig, cvc->pubkey); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -670,8 +674,8 @@ err_t cmdSigSelfVerify2(const octet anchor[], size_t anchor_len) err_t cmdSigExtr(const char* obj_name, const char* sig_name, const char* scope) { err_t code; - void* stack; - cmd_sig_t* sig; + void* state; + cmd_sig_t* sig; /* [1] */ size_t sig_len; // входной контроль if (!strIsValid(sig_name) || !strIsValid(obj_name) || !strIsValid(scope)) @@ -681,12 +685,14 @@ err_t cmdSigExtr(const char* obj_name, const char* sig_name, const char* scope) !strStartsWith(scope, "cert")) return ERR_CMD_PARAMS; // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(cmd_sig_t)); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + SIZE_MAX, + &sig); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; // читать подпись code = cmdSigRead(sig, &sig_len, sig_name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // извлечь сертификат? if (strStartsWith(scope, "cert")) { @@ -699,7 +705,7 @@ err_t cmdSigExtr(const char* obj_name, const char* sig_name, const char* scope) scope += strLen("cert"); if (!decIsValid(scope) || strLen(scope) != 1) code = ERR_CMD_PARAMS; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); num = decToU32(scope); // искать сертификат certs_len = sig->certs_len, cert = sig->certs, cert_len = pos = 0; @@ -735,7 +741,7 @@ err_t cmdSigExtr(const char* obj_name, const char* sig_name, const char* scope) code = cmdFileDup(obj_name, sig_name, size - sig_len, sig_len); } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -768,18 +774,20 @@ static err_t cmdSigPrintCertc(const cmd_sig_t* sig) err_t cmdSigPrint(const char* sig_name, const char* scope) { err_t code; - void* stack; - cmd_sig_t* sig; + void* state; + cmd_sig_t* sig; /* [1] */ // входной контроль if (!strIsValid(sig_name) || !strIsNullOrValid(scope)) return ERR_BAD_INPUT; // выделить и разметить память - code = cmdBlobCreate(stack, sizeof(cmd_sig_t)); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + SIZE_MAX, + &sig); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; // читать подпись code = cmdSigRead(sig, 0, sig_name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // печать всех полей if (scope == 0) { @@ -806,8 +814,8 @@ err_t cmdSigPrint(const char* sig_name, const char* scope) else code = ERR_CMD_PARAMS; // завершить - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); printf("\n"); - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_st.c b/cmd/core/cmd_st.c index 9ff6cea4..da80edd0 100644 --- a/cmd/core/cmd_st.c +++ b/cmd/core/cmd_st.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: self-tests \project bee2/cmd \created 2025.04.09 -\version 2025.06.09 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -328,10 +328,10 @@ err_t cmdStCrc(octet crc[32], const char* prefix) const size_t buf_size = 4096; err_t code; size_t count; - void* stack; - char* name; - octet* buf; void* state; + char* name; /* [count] */ + octet* buf; /* [buf_size] (|name) */ + void* hash_state; /* [beltHash_keep()] */ file_t file; // входной контроль if (!memIsValid(crc, 32) || !strIsNullOrValid(prefix)) @@ -340,34 +340,36 @@ err_t cmdStCrc(octet crc[32], const char* prefix) code = cmdSysModulePath(0, &count); ERR_CALL_CHECK(code); // выделить и разметить память - code = cmdBlobCreate(stack, MAX2(buf_size, count) + beltHash_keep()); + code = cmdBlobCreate2(state, + count, + buf_size | SIZE_HI, + beltHash_keep(), + SIZE_MAX, + &name, &buf, &hash_state); ERR_CALL_CHECK(code); - buf = (octet*)stack; - name = (char*)stack; - state = buf + MAX2(buf_size, count); // определить имя исполняемого модуля code = cmdSysModulePath(name, &count); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // открыть исполнямый модуль code = cmdFileOpen(file, name, "rb"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // начать хэширование - beltHashStart(state); + beltHashStart(hash_state); if (prefix) - beltHashStepH(prefix, strLen(prefix), state); + beltHashStepH(prefix, strLen(prefix), hash_state); // хэшировать файл do { if ((count = fileRead2(buf, buf_size, file)) == SIZE_MAX) code = ERR_FILE_READ; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); - beltHashStepH(buf, count, state); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); + beltHashStepH(buf, count, hash_state); } while (count); // закрыть файл code = cmdFileClose2(file); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // завершить - beltHashStepG(crc, state); - cmdBlobClose(stack); + beltHashStepG(crc, hash_state); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_stamp.c b/cmd/core/cmd_stamp.c index 143e613a..7a4ad3f1 100644 --- a/cmd/core/cmd_stamp.c +++ b/cmd/core/cmd_stamp.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: file stamps \project bee2/cmd \created 2025.04.21 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -54,11 +54,11 @@ static err_t cmdFileStamp( { const size_t buf_size = 4096; err_t code; - octet* stack; - octet* buf; /* [buf_size] */ - octet* stamp1; /* [10] */ - octet* stamp2; /* [10] */ - octet* state; /* [bashHash_keep()] */ + octet* state; + octet* buf; /* [buf_size] */ + octet* stamp1; /* [10] */ + octet* stamp2; /* [10] */ + octet* bash_state; /* [bashHash_keep()] */ file_t file; size_t count; bool_t stamped; @@ -66,19 +66,21 @@ static err_t cmdFileStamp( ASSERT((suffix == TRUE && stamp == 0) || memIsValid(stamp, 10)); ASSERT(strIsValid(name)); // выделить и разметить память - code = cmdBlobCreate(stack, buf_size + 20 + bashHash_keep()); + code = cmdBlobCreate2(state, + buf_size, + (size_t)10, + (size_t)10, + bashHash_keep(), + SIZE_MAX, + &buf, &stamp1, &stamp2, &bash_state); ERR_CALL_CHECK(code); - buf = stack; - stamp1 = buf + buf_size; - stamp2 = stamp1 + 10; - state = stamp2 + 10; // открыть файл code = cmdFileOpen(file, name, "rb"); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить размер файла if ((count = fileSize(file)) == SIZE_MAX) code = ERR_FILE_READ; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); // штамп в суффиксе? stamped = FALSE; if (suffix && count >= 10) @@ -87,32 +89,32 @@ static err_t cmdFileStamp( fileRead2(stamp2, 10, file) != 10 || !fileSeek(file, 0, SEEK_SET)) code = ERR_FILE_READ; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); memRev(stamp2, 10); stamped = (derOCTDec2(0, stamp2, 10, 8) == 10); memRev(stamp2, 10); } if (stamp == 0 && !stamped) code = ERR_MAX; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); // определить объем хэшируемой части файла count = stamped ? count - 10 : count; // хэшировать файл - bashHashStart(state, 32); + bashHashStart(bash_state, 32); while (count) { size_t c = MIN2(count, buf_size); if (fileRead2(buf, c, file) != c) code = ERR_FILE_READ; - ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(stack))); - bashHashStepH(buf, c, state); + ERR_CALL_HANDLE(code, (cmdFileClose(file), cmdBlobClose(state))); + bashHashStepH(buf, c, bash_state); count -= c; } // закрыть файл code = cmdFileClose2(file); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // завершить хэширование и кодировать - bashHashStepG(stamp1, 8, state); + bashHashStepG(stamp1, 8, bash_state); VERIFY(derOCTEnc(stamp1, stamp1, 8) == 10); memRev(stamp1, 10); // проверить суффикс @@ -127,7 +129,7 @@ static err_t cmdFileStamp( if (stamp) memCopy(stamp, stamp1, 10); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -180,26 +182,28 @@ err_t cmdStampVal(const char* name, const char* stamp_name) // проверить открепленный штамп else { - void* stack; - octet* stamp; - octet* stamp1; + void* state; + octet* stamp; /* [10] */ + octet* stamp1; /* [10] */ size_t count; // выделить и разметить память - code = cmdBlobCreate(stack, 20); + code = cmdBlobCreate2(state, + (size_t)10, + (size_t)10, + SIZE_MAX, + &stamp, &stamp1); ERR_CALL_CHECK(code); - stamp = (octet*)stack; - stamp1 = stamp + 10; // вычислить штамп code = cmdFileStamp(stamp, name, FALSE); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать штамп count = 10; code = cmdFileReadAll(stamp1, &count, stamp_name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // сравнить if (!memEq(stamp, stamp1, 10)) code = ERR_FILE_STAMP; - cmdBlobClose(stack); + cmdBlobClose(state); } return code; } @@ -209,22 +213,24 @@ err_t cmdStampSelfVal() const char* ext = ".stamp"; err_t code; size_t count; - void* stack; - octet* stamp; - octet* stamp1; - char* name; + void* state; + octet* stamp; /* [10] */ + octet* stamp1; /* [10] */ + char* name; /* [count + strLen(ext)] */ // определить длину имени исполняемого модуля code = cmdSysModulePath(0, &count); ERR_CALL_CHECK(code); // выделить и разметить память - code = cmdBlobCreate(stack, 10 + 10 + count + strLen(ext)); + code = cmdBlobCreate2(state, + (size_t)10, + (size_t)10, + count + strLen(ext), + SIZE_MAX, + &stamp, &stamp1, &name); ERR_CALL_CHECK(code); - stamp = (octet*)stack; - stamp1 = stamp + 10; - name = (char*)(stamp1 + 10); // определить имя исполняемого модуля code = cmdSysModulePath(name, &count); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить присоединенный штамп code = cmdFileStamp(stamp, name, TRUE); // в файле нет штампа? @@ -234,12 +240,12 @@ err_t cmdStampSelfVal() // прочитать отсоединенный штамп strCopy(name + strLen(name), ext); code = cmdFileReadAll(stamp1, &count, name); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить отсоединенный штамп if (!memEq(stamp, stamp1, 10)) code = ERR_FILE_STAMP; } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/core/cmd_sys.c b/cmd/core/cmd_sys.c index 92aaf89e..6dd692fa 100644 --- a/cmd/core/cmd_sys.c +++ b/cmd/core/cmd_sys.c @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2: system environment \project bee2/cmd \created 2025.04.20 -\version 2025.06.09 +\version 2025.09.30 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -47,7 +47,7 @@ err_t cmdSysExePath(char* path, size_t* count) len = wai_getExecutablePath(path, (int)(*count - 1), 0); if (len < 0) return ERR_SYS; - *count = (size_t)(len + 1); + *count = (size_t)len + 1; } return ERR_OK; } diff --git a/cmd/csr/csr.c b/cmd/csr/csr.c index 33b2f13b..7d7763c9 100644 --- a/cmd/csr/csr.c +++ b/cmd/csr/csr.c @@ -4,7 +4,7 @@ \brief Manage certificate signing requests \project bee2/cmd \created 2023.12.19 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -66,9 +66,9 @@ static err_t csrRewrap(int argc, char* argv[]) cmd_pwd_t pwd = 0; size_t privkey_len = 0; size_t csr_len; - void* stack; - octet* privkey; - octet* csr; + void* state; + octet* privkey; /* [privkey_len] */ + octet* csr; /* [csr_len] */ // самотестирование code = cmdStDo(CMD_ST_BIGN); ERR_CALL_CHECK(code); @@ -115,25 +115,27 @@ static err_t csrRewrap(int argc, char* argv[]) // определить длину запроса code = cmdFileReadAll(0, &csr_len, argv[1]); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, privkey_len + csr_len); + // выделить и разметить память + code = cmdBlobCreate2(state, + privkey_len, + csr_len, + SIZE_MAX, + &privkey, &csr); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - privkey = (octet*)stack; - csr = privkey + privkey_len; // определить личный ключ code = cmdPrivkeyRead(privkey, &privkey_len, argv[0], pwd); cmdPwdClose(pwd); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать запрос code = cmdFileReadAll(csr, &csr_len, argv[1]); ERR_CALL_CHECK(code); // перевыпустить запрос code = bpkiCSRRewrap(csr, csr_len, privkey, privkey_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // сохранить запрос code = cmdFileWrite(argv[2], csr, csr_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -149,7 +151,7 @@ static err_t csrVal(int argc, char* argv[]) { err_t code = ERR_OK; size_t csr_len; - void* stack; + void* state; octet* csr; // самотестирование code = cmdStDo(CMD_ST_BIGN); @@ -163,17 +165,19 @@ static err_t csrVal(int argc, char* argv[]) // определить длину запроса code = cmdFileReadAll(0, &csr_len, argv[0]); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, csr_len); + // выделить и разметить память + code = cmdBlobCreate2(state, + csr_len, + SIZE_MAX, + &csr); ERR_CALL_CHECK(code); - csr = stack; // прочитать запрос code = cmdFileReadAll(csr, &csr_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить запрос code = bpkiCSRUnwrap(0, 0, csr, csr_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/cvc/cvc.c b/cmd/cvc/cvc.c index 14c34432..429c3155 100644 --- a/cmd/cvc/cvc.c +++ b/cmd/cvc/cvc.c @@ -4,7 +4,7 @@ \brief Manage CV-certificates \project bee2/cmd \created 2022.07.12 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -522,11 +522,11 @@ static err_t cvcIss(int argc, char* argv[]) size_t certa_len; size_t req_len; size_t cert_len; - void* stack; - octet* certa; - octet* req; - octet* cert; - btok_cvc_t* cvc; + void* state; + octet* certa; /* [certa_len] */ + octet* req; /* [req_len] */ + octet* cert; /* [cert_len] */ + btok_cvc_t* cvc; /* [1] */ // самотестирование code = cmdStDo(CMD_ST_BIGN); ERR_CALL_CHECK(code); @@ -563,23 +563,24 @@ static err_t cvcIss(int argc, char* argv[]) ERR_CALL_HANDLE(code, cmdBlobClose(privkeya)); // построить оценку сверху для cert_len: req_len + расширение_подписи cert_len = req_len + (96 - 48); - // выделить память и разметить ее - code = cmdBlobCreate(stack, certa_len + req_len + cert_len + - sizeof(btok_cvc_t)); + // выделить и разметить память + code = cmdBlobCreate2(state, + certa_len, + req_len, + cert_len, + sizeof(btok_cvc_t), + SIZE_MAX, + &certa, &req, &cert, &cvc); ERR_CALL_HANDLE(code, cmdBlobClose(privkeya)); - certa = (octet*)stack; - req = certa + certa_len; - cert = req + req_len; - cvc = (btok_cvc_t*)(cert + cert_len); // прочитать сертификат code = cmdFileReadAll(certa, &certa_len, argv[1]); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // прочитать запрос code = cmdFileReadAll(req, &req_len, argv[2]); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // разобрать запрос code = btokCVCUnwrap(cvc, req, req_len, cvc->pubkey, 0); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // перенести в сертификат опции командной строки if (strLen(cvc0->holder)) strCopy(cvc->holder, cvc0->holder); @@ -603,11 +604,11 @@ static err_t cvcIss(int argc, char* argv[]) code = btokCVCIss(cert, &cert_len, cvc, certa, certa_len, privkeya, privkeya_len); cmdBlobClose(privkeya); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать сертификат code = cmdFileWrite(argv[3], cert, cert_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -631,10 +632,10 @@ static err_t cvcShorten(int argc, char* argv[]) octet* privkeya; size_t certa_len; size_t cert_len; - void* stack; - octet* certa; - octet* cert; - btok_cvc_t* cvc; + void* state; + octet* certa; /* [certa_len] */ + octet* cert; /* [cert_len] */ + btok_cvc_t* cvc; /* [1] */ // самотестирование code = cmdStDo(CMD_ST_BIGN); ERR_CALL_CHECK(code); @@ -668,37 +669,39 @@ static err_t cvcShorten(int argc, char* argv[]) ERR_CALL_HANDLE(code, cmdBlobClose(privkeya)); code = cmdFileReadAll(0, &cert_len, argv[2]); ERR_CALL_HANDLE(code, cmdBlobClose(privkeya)); - // выделить память и разметить ее - code = cmdBlobCreate(stack, certa_len + cert_len + sizeof(btok_cvc_t)); + // создать состояние + code = cmdBlobCreate2(state, + certa_len, + cert_len, + sizeof(btok_cvc_t), + SIZE_MAX, + &certa, &cert, &cvc); ERR_CALL_HANDLE(code, cmdBlobClose(privkeya)); - certa = (octet*)stack; - cert = certa + certa_len; - cvc = (btok_cvc_t*)(cert + cert_len); // прочитать сертификаты code = cmdFileReadAll(certa, &certa_len, argv[1]); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); code = cmdFileReadAll(cert, &cert_len, argv[2]); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // проверить сертификат code = btokCVCVal(cert, cert_len, certa, certa_len, 0); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // разобрать сертификат code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // срок действия действительно сокращается? if (memCmp(cvc->until, cvc0->until, 6) < 0) code = ERR_BAD_DATE; - ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(privkeya), cmdBlobClose(state))); // перенести в сертификат новую дату окончания memCopy(cvc->until, cvc0->until, 6); // выпустить сертификат code = btokCVCIss(cert, 0, cvc, certa, certa_len, privkeya, privkeya_len); cmdBlobClose(privkeya); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать сертификат code = cmdFileWrite(argv[2], cert, cert_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -717,15 +720,15 @@ cvc val [options] ... static err_t cvcVal(int argc, char* argv[]) { + const size_t cert_max_len = 512; err_t code; octet date[6]; int readc; - const size_t cert_max_len = 512; size_t cert_len; - void* stack; - octet* cert; - btok_cvc_t* cvc; - btok_cvc_t* cvc1; + void* state; + octet* cert; /* [cert_max_len] */ + btok_cvc_t* cvc; /* [1] */ + btok_cvc_t* cvc1; /* [1] */ // самотестирование code = cmdStDo(CMD_ST_BIGN); ERR_CALL_CHECK(code); @@ -739,43 +742,45 @@ static err_t cvcVal(int argc, char* argv[]) // проверить наличие/отсутствие файлов code = cmdFileValExist(argc, argv); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, cert_max_len + 2 * sizeof(btok_cvc_t)); + // создать состояние + code = cmdBlobCreate2(state, + cert_max_len, + sizeof(btok_cvc_t), + sizeof(btok_cvc_t), + SIZE_MAX, + &cert, &cvc, &cvc1); ERR_CALL_CHECK(code); - cert = (octet*)stack; - cvc = (btok_cvc_t*)(cert + cert_max_len); - cvc1 = cvc + 1; // прочитать первый сертификат code = cmdFileReadAll(0, &cert_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cert_len <= cert_max_len ? ERR_OK : ERR_BAD_CERT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdFileReadAll(cert, &cert_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // разобрать первый сертификат code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // цикл по сертификатам for (--argc, ++argv; argc--; ++argv) { // прочитать очередной сертификат code = cmdFileReadAll(0, &cert_len, *argv); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cert_len <= cert_max_len ? ERR_OK : ERR_BAD_CERT; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdFileReadAll(cert, &cert_len, *argv); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить очередной сертификат if (argc == 0 && !memIsZero(date, 6)) code = btokCVCVal2(cvc1, cert, cert_len, cvc, date); else code = btokCVCVal2(cvc1, cert, cert_len, cvc, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // подготовиться к проверке следующего сертификата memCopy(cvc, cvc1, sizeof(btok_cvc_t)); } // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -848,9 +853,9 @@ static err_t cvcExtr(int argc, char* argv[]) { err_t code; size_t cert_len; - void* stack; - octet* cert; - btok_cvc_t* cvc; + void* state; + octet* cert; /* [cert_len] */ + btok_cvc_t* cvc; /* [1] */ // обработать опции if (argc != 2) return ERR_CMD_PARAMS; @@ -862,21 +867,23 @@ static err_t cvcExtr(int argc, char* argv[]) // определить длину сертификата code = cmdFileReadAll(0, &cert_len, argv[0]); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, cert_len + sizeof(btok_cvc_t)); + // создать состояние + code = cmdBlobCreate2(state, + cert_len, + sizeof(btok_cvc_t), + SIZE_MAX, + &cert, &cvc); ERR_CALL_CHECK(code); - cert = (octet*)stack; - cvc = (btok_cvc_t*)(cert + cert_len); // прочитать сертификат code = cmdFileReadAll(cert, &cert_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // разобрать сертификат code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // сохранить открытый ключ code = cmdFileWrite(argv[1], cvc->pubkey, cvc->pubkey_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -891,11 +898,11 @@ cvc print [-{authority|holder|from|until|eid|esign|pubkey|sig}] static err_t cvcPrint(int argc, char* argv[]) { err_t code; - size_t cert_len; - void* stack; - octet* cert; - btok_cvc_t* cvc; const char* scope = 0; + size_t cert_len; + void* state; + octet* cert; /* [cert_len] */ + btok_cvc_t* cvc; /* [1] */ // обработать опции if (argc < 1 || argc > 2) return ERR_CMD_PARAMS; @@ -912,21 +919,23 @@ static err_t cvcPrint(int argc, char* argv[]) // определить длину сертификата code = cmdFileReadAll(0, &cert_len, argv[0]); ERR_CALL_CHECK(code); - // выделить память и разметить ее - code = cmdBlobCreate(stack, cert_len + sizeof(btok_cvc_t)); + // создать состояние + code = cmdBlobCreate2(state, + cert_len, + sizeof(btok_cvc_t), + SIZE_MAX, + &cert, &cvc); ERR_CALL_CHECK(code); - cert = (octet*)stack; - cvc = (btok_cvc_t*)(cert + cert_len); // прочитать сертификат code = cmdFileReadAll(cert, &cert_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // разобрать сертификат code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // печатать содержимое code = cmdCVCPrint(cvc, scope); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/cvr/cvr.c b/cmd/cvr/cvr.c index b5e99d40..861031de 100644 --- a/cmd/cvr/cvr.c +++ b/cmd/cvr/cvr.c @@ -4,7 +4,7 @@ \brief Manage CV-certificate rings \project bee2/cmd \created 2023.06.08 -\version 2025.06.09 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -151,16 +151,16 @@ static err_t cvrAdd(int argc, char* argv[]) { err_t code; cmd_pwd_t pwd; - void* stack; - size_t privkey_len; - octet* privkey; + size_t privkey_len; size_t certa_len; - octet* certa; size_t cert_len; - octet* cert; size_t sig_len; - cmd_sig_t* sig; - btok_cvc_t* cvc; + void* state; + octet* privkey; /* [privkey_len] */ + octet* certa; /* [certa_len] */ + octet* cert; /* [cert_len] */ + cmd_sig_t* sig; /* [1] */ + btok_cvc_t* cvc; /* [1] */ size_t ring_len; void* ring; octet* certs; @@ -188,48 +188,49 @@ static err_t cvrAdd(int argc, char* argv[]) // определить длину cert code = cmdFileReadAll(0, &cert_len, argv[4]); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - // создать и разметить стек - code = cmdBlobCreate(stack, privkey_len + certa_len + cert_len + - sizeof(cmd_sig_t) + sizeof(btok_cvc_t)); + // создать и разметить память + code = cmdBlobCreate2(state, + privkey_len, + certa_len, + cert_len, + sizeof(cmd_sig_t), + sizeof(btok_cvc_t), + SIZE_MAX, + &privkey, &certa, &cert, &sig, &cvc); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - privkey = (octet*)stack; - certa = privkey + privkey_len; - cert = certa + certa_len; - sig = (cmd_sig_t*)(cert + cert_len); - cvc = (btok_cvc_t*)(sig + 1); // прочитать личный ключ code = cmdPrivkeyRead(privkey, 0, argv[2], pwd); cmdPwdClose(pwd); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать certa code = cmdFileReadAll(certa, &certa_len, argv[3]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить соответствие личного ключа и certa code = btokCVCMatch(certa, certa_len, privkey, privkey_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать подпись code = cmdSigRead(sig, &sig_len, argv[5]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить вложенный в подпись сертификат if (sig->certs_len != certa_len || !memEq(sig->certs, certa, certa_len)) code = ERR_BAD_ANCHOR; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить подпись кольца code = cmdSigVerify2(argv[5], argv[5], certa, certa_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать cert code = cmdFileReadAll(cert, &cert_len, argv[4]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить cert code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(0, &ring_len, argv[5]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdBlobCreate(ring, ring_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdFileReadAll(ring, &ring_len, argv[5]); - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); certs = (octet*)ring; // искать сертификат ASSERT(sig_len <= ring_len); @@ -238,28 +239,28 @@ static err_t cvrAdd(int argc, char* argv[]) code = ERR_ALREADY_EXISTS; else if (code == ERR_NOT_FOUND) code = ERR_OK; - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); // добавить сертификат if (cert_len > ring_len) { blob_t r; code = cmdBlobResize(r, ring, ring_len - sig_len + cert_len); - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); ring = r, certs = (octet*)ring; } memCopy(certs + ring_len - sig_len, cert, cert_len); // записать сертификаты в файл code = cmdFileWrite(argv[5], certs, ring_len - sig_len + cert_len); cmdBlobClose(ring); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить текущую дату if (!tmDate2(date)) code = ERR_BAD_TIMER; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // подписать файл code = cmdSigSign(argv[5], argv[5], argv[3], date, privkey, privkey_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -275,16 +276,16 @@ static err_t cvrDel(int argc, char* argv[]) { err_t code; cmd_pwd_t pwd; - void* stack; size_t privkey_len; - octet* privkey; size_t certa_len; - octet* certa; size_t cert_len; - octet* cert; size_t sig_len; - cmd_sig_t* sig; - btok_cvc_t* cvc; + void* state; + octet* privkey; /* [privkey_len] */ + octet* certa; /* [certa_len] */ + octet* cert; /* [cert_len] */ + cmd_sig_t* sig; /* [1] */ + btok_cvc_t* cvc; /* [1] */ size_t ring_len; void* ring; octet* certs; @@ -313,53 +314,54 @@ static err_t cvrDel(int argc, char* argv[]) // определить длину cert code = cmdFileReadAll(0, &cert_len, argv[4]); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - // создать и разметить стек - code = cmdBlobCreate(stack, privkey_len + certa_len + cert_len + - sizeof(cmd_sig_t) + sizeof(btok_cvc_t)); + // выделить и разметить память + code = cmdBlobCreate2(state, + privkey_len, + certa_len, + cert_len, + sizeof(cmd_sig_t), + sizeof(btok_cvc_t), + SIZE_MAX, + &privkey, &certa, &cert, &sig, &cvc); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - privkey = (octet*)stack; - certa = privkey + privkey_len; - cert = certa + certa_len; - sig = (cmd_sig_t*)(cert + cert_len); - cvc = (btok_cvc_t*)(sig + 1); // прочитать личный ключ code = cmdPrivkeyRead(privkey, 0, argv[2], pwd); cmdPwdClose(pwd); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать certa code = cmdFileReadAll(certa, &certa_len, argv[3]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить соответствие личного ключа и certa code = btokCVCMatch(certa, certa_len, privkey, privkey_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать подпись code = cmdSigRead(sig, &sig_len, argv[5]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить вложенный в подпись сертификат if (sig->certs_len != certa_len || !memEq(sig->certs, certa, certa_len)) code = ERR_BAD_ANCHOR; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить подпись кольца code = cmdSigVerify2(argv[5], argv[5], certa, certa_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать cert code = cmdFileReadAll(cert, &cert_len, argv[4]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить cert code = btokCVCUnwrap(cvc, cert, cert_len, 0, 0); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(0, &ring_len, argv[5]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdBlobCreate(ring, ring_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdFileReadAll(ring, &ring_len, argv[5]); - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); certs = (octet*)ring; // искать сертификат ASSERT(sig_len <= ring_len); code = cmdCVCsFind(&offset, certs, ring_len - sig_len, cert, cert_len); - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); // удалить сертификат ASSERT(offset + cert_len + sig_len <= ring_len); memMove(certs + offset, certs + offset + cert_len, @@ -367,15 +369,15 @@ static err_t cvrDel(int argc, char* argv[]) // записать сертификаты в файл code = cmdFileWrite(argv[5], certs, ring_len - sig_len - cert_len); cmdBlobClose(ring); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить текущую дату if (!tmDate2(date)) code = ERR_BAD_TIMER; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // подписать файл code = cmdSigSign(argv[5], argv[5], argv[3], date, privkey, privkey_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -390,11 +392,11 @@ cvr val static err_t cvrVal(int argc, char* argv[]) { err_t code; - void* stack; size_t certa_len; - octet* certa; size_t sig_len; - cmd_sig_t* sig; + void* state; + octet* certa; /* [certa_len] */ + cmd_sig_t* sig; /* [1] */ size_t ring_len; void* ring; octet* certs; @@ -411,38 +413,40 @@ static err_t cvrVal(int argc, char* argv[]) // определить длину certa code = cmdFileReadAll(0, &certa_len, argv[0]); ERR_CALL_CHECK(code); - // создать и разметить стек - code = cmdBlobCreate(stack, certa_len + sizeof(cmd_sig_t)); + // выделить и разметить память + code = cmdBlobCreate2(state, + certa_len, + sizeof(cmd_sig_t), + SIZE_MAX, + &certa, &sig); ERR_CALL_CHECK(code); - certa = (octet*)stack; - sig = (cmd_sig_t*)(certa + certa_len); // прочитать certa code = cmdFileReadAll(certa, &certa_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать подпись code = cmdSigRead(sig, &sig_len, argv[1]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить вложенный в подпись сертификат if (sig->certs_len != certa_len || !memEq(sig->certs, certa, certa_len)) code = ERR_BAD_ANCHOR; - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // проверить подпись кольца code = cmdSigVerify2(argv[1], argv[1], certa, certa_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(0, &ring_len, argv[1]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdBlobCreate(ring, ring_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = cmdFileReadAll(ring, &ring_len, argv[1]); - ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(stack))); + ERR_CALL_HANDLE(code, (cmdBlobClose(ring), cmdBlobClose(state))); certs = (octet*)ring; // проверить сертификаты ASSERT(sig_len <= ring_len); code = cmdCVCsCheck(certs, ring_len - sig_len); // завершить cmdBlobClose(ring); - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -457,13 +461,13 @@ cvr find static err_t cvrFind(int argc, char* argv[]) { err_t code; - void* stack; size_t cert_len; - octet* cert; size_t sig_len; - cmd_sig_t* sig; size_t ring_len; - octet* certs; + void* state; + octet* cert; /* [cert_len] */ + cmd_sig_t* sig; /* [1] */ + octet* certs; /* [ring_len] (|sig) */ // обработать опции if (argc != 2) return ERR_CMD_PARAMS; @@ -477,24 +481,26 @@ static err_t cvrFind(int argc, char* argv[]) code = cmdFileReadAll(0, &ring_len, argv[0]); ERR_CALL_CHECK(code); // выделить и разметить память - code = cmdBlobCreate(stack, cert_len + MAX2(sizeof(cmd_sig_t), ring_len)); + code = cmdBlobCreate2(state, + cert_len, + sizeof(cmd_sig_t), + ring_len | SIZE_HI, + SIZE_MAX, + &cert, &sig, &certs); ERR_CALL_CHECK(code); - cert = (octet*)stack; - certs = cert + cert_len; - sig = (cmd_sig_t*)certs; // прочитать cert code = cmdFileReadAll(cert, &cert_len, argv[1]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить длину подписи code = cmdSigRead(sig, &sig_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(certs, &ring_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // найти сертификат code = cmdCVCsFind(0, certs, ring_len - sig_len, cert, cert_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -511,11 +517,11 @@ static err_t cvrExtr(int argc, char* argv[]) err_t code; const char* scope; size_t num; - void* stack; size_t sig_len; - cmd_sig_t* sig; size_t ring_len; - octet* certs; + void* state; + cmd_sig_t* sig; /* [1] */ + octet* certs; /* [ring_len] (|sig) */ size_t offset; size_t cert_len; // обработать опции @@ -536,23 +542,25 @@ static err_t cvrExtr(int argc, char* argv[]) code = cmdFileReadAll(0, &ring_len, argv[1]); ERR_CALL_CHECK(code); // выделить и разметить память - code = cmdBlobCreate(stack, MAX2(sizeof(cmd_sig_t), ring_len)); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + ring_len | SIZE_HI, + SIZE_MAX, + &sig, &certs); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; - certs = (octet*)stack; // определить длину подписи code = cmdSigRead(sig, &sig_len, argv[1]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(certs, &ring_len, argv[1]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // найти сертификат code = cmdCVCsGet(&offset, &cert_len, certs, ring_len - sig_len, num); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать сертификат в файл code = cmdFileWrite(argv[2], certs + offset, cert_len); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -568,11 +576,11 @@ static err_t cvrPrint(int argc, char* argv[]) { err_t code; const char* scope; - void* stack; size_t sig_len; - cmd_sig_t* sig; size_t ring_len; - octet* certs; + void* state; + cmd_sig_t* sig; /* [1] */ + octet* certs; /* [ring_len] (|sig) */ size_t count; // обработать опции if (argc == 1) @@ -588,20 +596,22 @@ static err_t cvrPrint(int argc, char* argv[]) code = cmdFileReadAll(0, &ring_len, argv[0]); ERR_CALL_CHECK(code); // выделить и разметить память - code = cmdBlobCreate(stack, MAX2(sizeof(cmd_sig_t), ring_len)); + code = cmdBlobCreate2(state, + sizeof(cmd_sig_t), + ring_len | SIZE_HI, + SIZE_MAX, + &sig, &certs); ERR_CALL_CHECK(code); - sig = (cmd_sig_t*)stack; - certs = (octet*)stack; // определить длину подписи code = cmdSigRead(sig, &sig_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // прочитать кольцо code = cmdFileReadAll(certs, &ring_len, argv[0]); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить число сертификатов ASSERT(sig_len <= ring_len); code = cmdCVCsCount(&count, certs, ring_len - sig_len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // печатать if (!scope) { @@ -615,7 +625,7 @@ static err_t cvrPrint(int argc, char* argv[]) else printf("%u\n", (unsigned)count); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/cmd/fmt/fmt.c b/cmd/fmt/fmt.c new file mode 100644 index 00000000..a2cc7571 --- /dev/null +++ b/cmd/fmt/fmt.c @@ -0,0 +1,256 @@ +/* +******************************************************************************* +\file fmt.c +\brief Format-preserving encryption +\project bee2/cmd +\created 2025.06.12 +\version 2025.09.22 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bee2/cmd.h" + +/* +******************************************************************************* +Утилита fmt + +Функционал: +- шифрование с сохранением формата; +- секретные итераторы по строкам формата. + +Пример: + bee2cmd fmt enc -b10 -pass pass:zed 123456 + bee2cmd fmt next -b10 -pass pass:zed 123456 +******************************************************************************* +*/ + +static const char _name[] = "fmt"; +static const char _descr[] = "format-preserving encryption"; + +static int fmtUsage() +{ + printf( + "bee2cmd/%s: %s\n" + "Usage:\n" + " fmt enc -b -pass \n" + " encrypt \n" + " fmt dec -b -pass \n" + " decrypt \n" + " fmt next -b -pass \n" + " next to \n" + " fmt prev -b -pass \n" + " prev to \n" + " options:\n" + " -b -- format of :\n" + " -b10 -- decimal\n" + " -pass -- password for operation\n" + , + _name, _descr + ); + return -1; +} + +/* +******************************************************************************* +Вспомогательные функции +******************************************************************************* +*/ + +static bool_t fmtBaseIsValid(size_t base) +{ + return base == 10; +} + +static bool_t fmtStrIsValid(const char* str, size_t base) +{ + ASSERT(fmtBaseIsValid(base)); + return decIsValid(str); +} + +static err_t fmtStrEnc(char* str, size_t base, const cmd_pwd_t pwd) +{ + return ERR_NOT_IMPLEMENTED; +} + +static err_t fmtStrPrint(const char* str) +{ + (void)printf("%s\n", str); + return ERR_OK; +} + +/* +******************************************************************************* +Зашифрование + +fmt enc -b -pass +******************************************************************************* +*/ + +static err_t fmtEnc(int argc, char* argv[]) +{ + err_t code = ERR_OK; + size_t base = 0; + cmd_pwd_t pwd = 0; + void* state = 0; + char* str; + // самотестирование + code = cmdStDo(CMD_ST_BELS | CMD_ST_BELT | CMD_ST_BRNG); + ERR_CALL_CHECK(code); + // разбор опций + while (argc && strStartsWith(*argv, "-")) + { + if (strStartsWith(*argv, "-b")) + { + char* str = *argv + strLen("-b"); + if (base) + { + code = ERR_CMD_DUPLICATE; + break; + } + if (!decIsValid(str) || decCLZ(str) || strLen(str) > 5 || + !fmtBaseIsValid(base = (size_t)decToU32(str))) + { + code = ERR_CMD_PARAMS; + break; + } + ++argv, --argc; + } + else if (strEq(*argv, "-pass")) + { + if (pwd) + { + code = ERR_CMD_DUPLICATE; + break; + } + ++argv, --argc; + if (!argc) + { + code = ERR_CMD_PARAMS; + break; + } + code = cmdPwdRead(&pwd, *argv); + if (code != ERR_OK) + break; + ASSERT(cmdPwdIsValid(pwd)); + ++argv, --argc; + } + else + { + code = ERR_CMD_PARAMS; + break; + } + } + if (code == ERR_OK && (!pwd || argc != 1)) + code = ERR_CMD_PARAMS; + ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); + // проверить формат + if (!fmtStrIsValid(argv[0], base)) + code = ERR_BAD_FORMAT; + ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); + // выделить и разметить память + code = cmdBlobCreate2(state, + strLen(argv[0]) + 1, + SIZE_MAX, + &str); + ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); + strCopy(str, argv[0]); + // зашифровать + code = fmtStrEnc(str, base, pwd); + cmdPwdClose(pwd); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); + // напечатать + code = fmtStrPrint(str); + // завершить + cmdBlobClose(state); + return code; +} + +/* +******************************************************************************* +Расшифрование + +fmt dec -b -pass +******************************************************************************* +*/ + +static err_t fmtDec(int argc, char* argv[]) +{ + return ERR_NOT_IMPLEMENTED; +} + +/* +******************************************************************************* +Следующая строка + +fmt next -b -pass +******************************************************************************* +*/ + +static err_t fmtNext(int argc, char* argv[]) +{ + return ERR_NOT_IMPLEMENTED; +} + +/* +******************************************************************************* +Предыдущая строка + +fmt prev -b -pass +******************************************************************************* +*/ + +static err_t fmtPrev(int argc, char* argv[]) +{ + return ERR_NOT_IMPLEMENTED; +} + +/* +******************************************************************************* +Главная функция +******************************************************************************* +*/ + +static int fmtMain(int argc, char* argv[]) +{ + err_t code; + // справка + if (argc != 5) + return fmtUsage(); + // разбор команды + ++argv, --argc; + if (strEq(argv[0], "enc")) + code = fmtEnc(argc - 1, argv + 1); + else if (strEq(argv[0], "dec")) + code = fmtDec(argc - 1, argv + 1); + else if (strEq(argv[0], "next")) + code = fmtNext(argc - 1, argv + 1); + else if (strEq(argv[0], "prev")) + code = fmtPrev(argc - 1, argv + 1); + else + code = ERR_CMD_NOT_FOUND; + // завершить + if (code != ERR_OK) + printf("bee2cmd/%s: %s\n", _name, errMsg(code)); + return code != ERR_OK ? -1 : 0; +} + +/* +******************************************************************************* +Инициализация +******************************************************************************* +*/ + +err_t fmtInit() +{ + return cmdReg(_name, _descr, fmtMain); +} diff --git a/cmd/include/bee2/cmd.h b/cmd/include/bee2/cmd.h index f6fa5eaa..17d9f7f7 100644 --- a/cmd/include/bee2/cmd.h +++ b/cmd/include/bee2/cmd.h @@ -4,7 +4,7 @@ \brief Command-line interface to Bee2 \project bee2/cmd \created 2022.06.09 -\version 2025.06.10 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -33,7 +33,11 @@ extern "C" { #define cmdBlobCreate(blob, size) \ (((blob) = blobCreate(size)) ? ERR_OK : ERR_OUTOFMEMORY) -/*! \brief Изменение размера блоба */ +/*! \brief Создание блоба с разметкой памяти */ +#define cmdBlobCreate2(blob, ...) \ + (((blob) = blobCreate2(__VA_ARGS__)) ? ERR_OK : ERR_OUTOFMEMORY) + + /*! \brief Изменение размера блоба */ #define cmdBlobResize(b, blob, size)\ (((b) = blobResize(blob, size)) ? ERR_OK : ERR_OUTOFMEMORY) diff --git a/cmd/kg/kg.c b/cmd/kg/kg.c index 3bf924ee..95db93c2 100644 --- a/cmd/kg/kg.c +++ b/cmd/kg/kg.c @@ -4,7 +4,7 @@ \brief Generate and manage private keys \project bee2/cmd \created 2022.06.08 -\version 2025.06.09 +\version 2025.09.22 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -106,9 +106,9 @@ static err_t kgGen(int argc, char* argv[]) size_t len = 0; cmd_pwd_t pwd = 0; bign_params params[1]; - void* stack = 0; - octet* privkey; - octet* pubkey; + void* state = 0; + octet* privkey; /* [len] */ + octet* pubkey; /* [2 len] */ // самотестирование code = cmdStDo(CMD_ST_BELS | CMD_ST_BELT | CMD_ST_BIGN | CMD_ST_BRNG); ERR_CALL_CHECK(code); @@ -171,20 +171,22 @@ static err_t kgGen(int argc, char* argv[]) // запустить ГСЧ code = cmdRngStart(TRUE); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - // выделить память - code = cmdBlobCreate(stack, 3 * len); + // выделить и разметить память + code = cmdBlobCreate2(state, + len, + 2 * len, + SIZE_MAX, + &privkey, &pubkey); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); // генерировать ключ - privkey = (octet*)stack; - pubkey = privkey + len; code = len == 24 ? bign96KeypairGen(privkey, pubkey, params, rngStepR, 0) : bignKeypairGen(privkey, pubkey, params, rngStepR, 0); - ERR_CALL_HANDLE(code, (cmdBlobClose(stack), cmdPwdClose(pwd))); + ERR_CALL_HANDLE(code, (cmdBlobClose(state), cmdPwdClose(pwd))); // обновить ключ ГСЧ rngRekey(); // сохранить ключ code = cmdPrivkeyWrite(privkey, len, argv[0], pwd); - cmdBlobClose(stack); + cmdBlobClose(state); cmdPwdClose(pwd); return code; } @@ -354,10 +356,10 @@ static err_t kgExtr(int argc, char* argv[]) err_t code = ERR_OK; cmd_pwd_t pwd = 0; bign_params params[1]; - void* stack; size_t len = 0; - octet* privkey; - octet* pubkey; + void* state; + octet* privkey; /* [len] */ + octet* pubkey; /* [2 len] */ // самотестирование code = cmdStDo(CMD_ST_BELS | CMD_ST_BELT | CMD_ST_BIGN); ERR_CALL_CHECK(code); @@ -401,25 +403,27 @@ static err_t kgExtr(int argc, char* argv[]) // определить длину личного ключа code = cmdPrivkeyRead(0, &len, argv[0], pwd); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - // выделить память и разметить ее - code = cmdBlobCreate(stack, len + 2 * len); + // выделить и разметить память + code = cmdBlobCreate2(state, + len, + 2 * len, + SIZE_MAX, + &privkey, &pubkey); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - privkey = (octet*)stack; - pubkey = privkey + len; // определить личный ключ code = cmdPrivkeyRead(privkey, &len, argv[0], pwd); cmdPwdClose(pwd); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить открытый ключ code = kgParamsStd(params, len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = len == 24 ? bign96PubkeyCalc(pubkey, params, privkey) : bignPubkeyCalc(pubkey, params, privkey); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // записать открытый ключ code = cmdFileWrite(argv[1], pubkey, len * 2); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } @@ -436,11 +440,11 @@ static err_t kgPrint(int argc, char* argv[]) err_t code = ERR_OK; cmd_pwd_t pwd = 0; bign_params params[1]; - void* stack; size_t len = 0; - octet* privkey; - octet* pubkey; - char* hex; + void* state; + octet* privkey; /* [len] */ + octet* pubkey; /* [2 len] */ + char* hex; /* [4 len + 1] */ // самотестирование code = cmdStDo(CMD_ST_BELS | CMD_ST_BELT); ERR_CALL_CHECK(code); @@ -482,26 +486,28 @@ static err_t kgPrint(int argc, char* argv[]) code = cmdPrivkeyRead(0, &len, argv[0], pwd); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); // выделить память и разметить ее - code = cmdBlobCreate(stack, len + 2 * len + 4 * len + 1); + code = cmdBlobCreate2(state, + len, + 2 * len, + 4 * len + 1, + SIZE_MAX, + &privkey, &pubkey, &hex); ERR_CALL_HANDLE(code, cmdPwdClose(pwd)); - privkey = (octet*)stack; - pubkey = privkey + len; - hex = (char*)(pubkey + 2 * len); // определить личный ключ code = cmdPrivkeyRead(privkey, &len, argv[0], pwd); cmdPwdClose(pwd); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // определить открытый ключ code = kgParamsStd(params, len); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); code = len == 24 ? bign96PubkeyCalc(pubkey, params, privkey) : bignPubkeyCalc(pubkey, params, privkey); - ERR_CALL_HANDLE(code, cmdBlobClose(stack)); + ERR_CALL_HANDLE(code, cmdBlobClose(state)); // печатать открытый ключ hexFrom(hex, pubkey, len * 2); printf("%s\n", hex); // завершить - cmdBlobClose(stack); + cmdBlobClose(state); return code; } diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a8c7d573..60f5cfed 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -17,4 +17,4 @@ add_custom_command(OUTPUT ${doxy_html_index_file} add_custom_target(docbee2 ALL DEPENDS ${doxy_html_index_file}) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/html - DESTINATION share/bee2/doc) + DESTINATION ${CMAKE_INSTALL_DATADIR}/bee2/doc) diff --git a/doc/bee2.doxy b/doc/bee2.doxy index f122cc68..e499bb86 100644 --- a/doc/bee2.doxy +++ b/doc/bee2.doxy @@ -922,7 +922,7 @@ WARN_LINE_FORMAT = "at line $line of file $file" # specified the warning and error messages are written to standard output # (stdout). -WARN_LOGFILE = +WARN_LOGFILE = warnings.log #--------------------------------------------------------------------------- # Configuration options related to the input files diff --git a/include/bee2/core/blob.h b/include/bee2/core/blob.h index 0f2dd124..07bb9f14 100644 --- a/include/bee2/core/blob.h +++ b/include/bee2/core/blob.h @@ -4,7 +4,7 @@ \brief Blobs \project bee2 [cryptographic library] \created 2012.04.01 -\version 2022.06.17 +\version 2025.08.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -60,6 +60,27 @@ blob_t blobCreate( size_t size /*!< [in] размер */ ); +/*! \brief Создание блоба с разметкой памяти + + Создается блоб blob для хранения фрагментов памяти [с1]p1, [с2]p2, ...., + [сn]pn. Фрагменты описываются параметрами c1 и .... Описание имеет вид: + c1, pp1, c2, pp2, ..., cn, ppn, SIZE_MAX, + где сi -- длина фрагмента в октетах (size_t), ppi -- указатель на pi + (const void**), SIZE_MAX -- маркер окончания списка параметров. + Действуют правила функции memSlice(). В частности, + - указатели pi выровнены на границу фундаментального блока; + - при установке в ci флага SIZE_HI указатель pi повторяет предыдущий, если + таковой имеется. + \return Дескриптор блоба. Нулевой дескриптор возвращается при + нехватке памяти. + \post Указатели pi, если они формируются, выровнены на границу + фундаментального блока. +*/ +blob_t blobCreate2( + size_t c1, /*!< [in] начало описания фрагментов памяти */ + ... /*!< [in,out] окончание описания */ +); + /*! \brief Корректный блоб? Проверяется корректность блоба blob. diff --git a/include/bee2/core/der.h b/include/bee2/core/der.h index 6ef11c63..bbedc35e 100644 --- a/include/bee2/core/der.h +++ b/include/bee2/core/der.h @@ -4,7 +4,7 @@ \brief Distinguished Encoding Rules \project bee2 [cryptographic library] \created 2014.04.21 -\version 2025.04.22 +\version 2025.08.08 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -189,7 +189,7 @@ bool_t derIsValid2( распознаваемый реализацией тег (см. далее), то он корректно декодируется; - если der конструктивен, т.е. содержит вложенные der-поля, то derIsValid(d, count) == TRUE для каждого такого поля d; - - глубина вложенности не превышает 32; + - глубина вложенности не превышает 32. \return Признак корректности. */ bool_t derIsValid3( diff --git a/include/bee2/core/hex.h b/include/bee2/core/hex.h index 46935f05..e667d347 100644 --- a/include/bee2/core/hex.h +++ b/include/bee2/core/hex.h @@ -4,7 +4,7 @@ \brief Hexadecimal strings \project bee2 [cryptographic library] \created 2015.10.29 -\version 2025.05.07 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -106,7 +106,6 @@ bool_t hexEq( const char* hex /*!< [in] шестнадцатеричная строка */ ); -bool_t SAFE(hexEq)(const void* buf, const char* hex); bool_t FAST(hexEq)(const void* buf, const char* hex); /*! \brief Совпадает с префиксом шестнадцатеричной строки? @@ -125,7 +124,6 @@ bool_t hexEq2( size_t len /*!< [in] длина префикса */ ); -bool_t SAFE(hexEq2)(const void* buf, const char* hex, size_t len); bool_t FAST(hexEq2)(const void* buf, const char* hex, size_t len); /*! \brief Реверсивно совпадает с шестнадцатеричной строкой? @@ -150,7 +148,6 @@ bool_t hexEqRev( const char* hex /*!< [in] шестнадцатеричная строка */ ); -bool_t SAFE(hexEqRev)(const void* buf, const char* hex); bool_t FAST(hexEqRev)(const void* buf, const char* hex); /*! \brief Реверсивно совпадает с префиксом шестнадцатеричной строки? @@ -166,10 +163,9 @@ bool_t FAST(hexEqRev)(const void* buf, const char* hex); bool_t hexEqRev2( const void* buf, /*!< [in] буфер */ const char* hex, /*!< [in] шестнадцатеричная строка */ - size_t /*!< [in] длина префикса */ + size_t len /*!< [in] длина префикса */ ); -bool_t SAFE(hexEqRev2)(const void* buf, const char* hex, size_t len); bool_t FAST(hexEqRev2)(const void* buf, const char* hex, size_t len); /*! \brief Кодирование шестнадцатеричной строкой diff --git a/include/bee2/core/mem.h b/include/bee2/core/mem.h index 86b102aa..d7a91699 100644 --- a/include/bee2/core/mem.h +++ b/include/bee2/core/mem.h @@ -4,7 +4,7 @@ \brief Memory management \project bee2 [cryptographic library] \created 2012.07.16 -\version 2025.04.25 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -34,7 +34,7 @@ extern "C" { Реализованы или переопределены манипуляции над буферами памяти, которые интерпретируются как строки октетов. -Функции xxTo и xxFrom выполняют преобразования между буферами +Функции xxTo() и xxFrom() выполняют преобразования между буферами памяти и другими структурами данных. Могут быть функции двух типов: простые и сложные. В простых функциях объем памяти для размещения преобразованных данных сразу известен. В простые функции передается @@ -50,10 +50,31 @@ extern "C" { и, наоборот, при сохранении слова в памяти выполняется реверс октетов слова. -\pre В функции передаются корректные буферы памяти. +В функциях memAlloc(), memRealloc(), memSlice() и memSlice2() указатели +выравниваются на границу фундаментального блока. Фундаментальный блок +инкапсулирует все скалярные типы Bee2. По адресу, выровненному на границу +блока, можно размещать любой скалярный тип и, следовательно, любой объект. + +\pre Если не оговорено противное, в функции передаются корректные буферы +памяти. ******************************************************************************* */ +/* \brief Фундаментальный блок + \warning Выравнивание на границу dword не гарантируется. Если гарантии + нужны, то в mem_align_t следует включить поле типа dword. + \remark Указатели void* и void(*)() приводятся отдельно, поскольку + равенство sizeof(void*) == sizeof(void(*)()) может нарушаться + (см. https://stackoverflow.com/questions/12358843/). +*/ +typedef union +{ + word w; + size_t s; + void *p; + void (*fp)(); +} mem_align_t; + /* ******************************************************************************* Стандартные функции @@ -71,7 +92,6 @@ void memCopy( size_t count /*< [in] число октетов */ ); - /*! Копировать [count]src в [count]dest, если указатели src и dest ненулевые. */ #define memCopyIf(dest, src, count)\ @@ -110,21 +130,38 @@ void memNeg( size_t count /*< [in] число октетов */ ); +/*! \brief Указатель выровнен на границу блока? + + Проверяется, что указатель p выровнен на границу блока из align октетов. + \return Проверяемый признак. +*/ +bool_t memIsAligned( + const void* p, /*!< [in] указатель */ + size_t alignment /*!< [in] длина блока */ +); + /*! \brief Выделение блока памяти + Выделяется блок динамической памяти из count октетов. \return Указатель на блок памяти или 0, если памяти не хватает. - \remark Блок выделяется, даже если count == 0. + \post Возвращаемый указатель p выровнен на границу фундаментального + блока: memIsAligned(p, sizeof(mem_block_t)) == TRUE. + \remark Разрешается вызов memAlloc(0). Результатом вызова может быть + нулевой указатель. Его можно передавать в memRealloc() и memFree(). */ void* memAlloc( size_t count /*!< [in] размер блока */ ); /*! \brief Изменение размера блока памяти + Размер блока динамической памяти buf устанавливается равным count. При необходимости блок перемещается в памяти. Содержимое блока максимально сохраняется. - \return Указатель на блок памяти с новым размером - или 0, если count == 0 или памяти не хватает. + \return Указатель на блок памяти с новым размером или 0, если count == 0 + или памяти не хватает. + \post Возвращаемый указатель p выровнен на границу фундаментального + блока: memIsAligned(p, sizeof(mem_block_t)) == TRUE. \remark memRealloc(buf, 0) равносильно memFree(buf). */ void* memRealloc( @@ -164,17 +201,6 @@ bool_t memIsValid( #define memIsNullOrValid(buf, count)\ ((buf) == 0 || memIsValid(buf, count)) -/*! \brief Буфер выровнен на границу? - - Проверяется, что buf выровнен на границу size-байтового блока. - \return Проверяемый признак. -*/ -bool_t memIsAligned( - const void* buf, /*!< [in] буфер */ - size_t size /*!< [in] длина блока */ -); - - /*! \brief Проверка совпадения Проверяется, что содержимое буферов [count]buf1 и [count]buf2 совпадает. @@ -187,7 +213,6 @@ bool_t memEq( size_t count /*!< [in] размер буферов */ ); -bool_t SAFE(memEq)(const void* buf1, const void* buf2, size_t count); bool_t FAST(memEq)(const void* buf1, const void* buf2, size_t count); /*! \brief Сравнение @@ -207,7 +232,6 @@ int memCmp( size_t count /*!< [in] размер буферов */ ); -int SAFE(memCmp)(const void* buf1, const void* buf2, size_t count); int FAST(memCmp)(const void* buf1, const void* buf2, size_t count); /*! \brief Обратное сравнение @@ -226,7 +250,6 @@ int memCmpRev( size_t count /*!< [in] размер буферов */ ); -int SAFE(memCmpRev)(const void* buf1, const void* buf2, size_t count); int FAST(memCmpRev)(const void* buf1, const void* buf2, size_t count); /*! \brief Очистить буфер памяти @@ -251,7 +274,6 @@ bool_t memIsZero( size_t count /*!< [in] размер буфера */ ); -bool_t SAFE(memIsZero)(const void* buf, size_t count); bool_t FAST(memIsZero)(const void* buf, size_t count); /*! \brief Размер значащей части буфера @@ -280,7 +302,6 @@ bool_t memIsRep( octet o /*!< [in] значение */ ); -bool_t SAFE(memIsRep)(const void* buf, size_t count, octet o); bool_t FAST(memIsRep)(const void* buf, size_t count, octet o); /*! \brief Объединение двух буферов @@ -407,11 +428,6 @@ void memSwap( size_t count /*!< [in] число октетов */ ); -/* -******************************************************************************* -Реверс октетов -******************************************************************************* -*/ /*! \brief Реверс октетов @@ -422,6 +438,73 @@ void memRev( size_t count /*!< [in] размер буфера */ ); +/* +******************************************************************************* +Разметка памяти +******************************************************************************* +*/ + +/*! \brief Разметка буфера памяти + + Буфер buf разбивается на фрагменты [c1]p1, ..., [cn]pn. Фрагменты + описываются параметрами c1 и ... . Описание имеет вид: + с1, c2, ..., cn, SIZE_MAX, pp1, pp2, ..., ppn, + где сi -- длина фрагмента в октетах (size_t), SIZE_MAX -- маркер окончания + списка длин, ppi -- указатель на pi (const void**). + При установке в сi флага SIZE_HI указатель pi повторяет предыдущий, если + таковой имеется. Это позволяет использовать один и тот же участок памяти + в разные моменты времени для размещения разных объектов. + \pre Указатель buf выровнен на границу фундаментального блока: + memIsAligned(buf, sizeof(mem_block_t)) == TRUE + \pre Указатели ppi корректны. + \post Указатели pi выровнены на границу фундаментального блока: + memIsAligned(pi, sizeof(mem_block_t)) == TRUE. +*/ +void memSlice( + const void* buf, /*!< [in] буфер */ + size_t c1, /*!< [in] начало описания фрагментов памяти */ + ... /*!< [in,out] окончание описания */ +); + +/*! \brief Размер размечаемого буфера памяти + + Определяется объем памяти для размещения фрагментов памяти длин + с1, с2, ..., cn, заданных параметрами c1 и .... Описание имеет вид: + c1, c2, ..., cn, SIZE_MAX. + Действуют соглашения memSlice(). + \return Суммарная длина фрагментов с учетом выравнивания и возможных + пересечений фрагментов. + \warning Суммарная длина фрагментов не обязательно кратна длине + фундаментального блока. Добиться кратности можно, передавая в качестве cn + величину SIZE_0. +*/ +size_t memSliceSize( + size_t c1, /*!< [in] начало описания длин фрагментов памяти */ + ... /*!< [in,out] окончание описания */ +); + +/*! \brief Cледующий фрагмент размеченной памяти + + Определяется указатель на фрагмент памяти, следующий за [count]ptr. + \expect Память размечена по правилам memSlice(). + \return Указатель на следующий фрагмент. +*/ +void* memSliceNext( + void* ptr, /*!< [in] указатель на начало фрагмента */ + size_t count /*!< [in] длина фрагмента */ +); + +/*! \brief Cледующий фрагмент размеченной постоянной памяти + + Определяется указатель на фрагмент постоянной памяти, следующий за [count]ptr. + \expect Память размечена по правилам memSlice(). + \return Указатель на следующий фрагмент. +*/ +const void* memSliceNext2( + const void* ptr, /*!< [in] указатель на начало фрагмента */ + size_t count /*!< [in] длина фрагмента */ +); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/bee2/core/rng.h b/include/bee2/core/rng.h index 02e8643c..280f3226 100644 --- a/include/bee2/core/rng.h +++ b/include/bee2/core/rng.h @@ -4,7 +4,7 @@ \brief Entropy sources and random number generators \project bee2 [cryptographic library] \created 2014.10.13 -\version 2023.12.19 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -141,9 +141,6 @@ bool_t rngTestFIPS4( меньшее count и возможно нулевое) и источник сохранил работоспособность, ERR_BAD_ENTROPY, если получено меньше чем count октетов и источник отказал, или другой код ошибки. - \warning Если при работе с источниками "trng", "trng2" длина выходного - буфера меньше 4, то функция возвратит ERR_OK, но ни одного октета данных - сгенерировано не будет. \remark Ошибкой не считается ситуация, когда сгенерировано меньше чем count октетов. Данная ситуация может быть связана с ожиданием накопления наблюдений. diff --git a/include/bee2/core/safe.h b/include/bee2/core/safe.h index 1c25e066..7d81f58c 100644 --- a/include/bee2/core/safe.h +++ b/include/bee2/core/safe.h @@ -4,7 +4,7 @@ \brief Safe (regular) calculations \project bee2 [cryptographic library] \created 2013.10.07 -\version 2025.04.25 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -46,25 +46,24 @@ extern "C" { - цикл с переменным числом шагов (условие выхода из цикла определяется входными данными); - нерегулярные композиционные блоки (например, вызываемые функции); -- обрабатываемыt данные не могут быть секретными; +- обрабатываемые данные не могут быть секретными; - логика работы функции противоречит регулярности (например, функция рассчитывает характеристики данных). . Функция f() может быть представлена в двух редакциях: регулярной и ускоренной -нерегулярной. Имена редакциям назначаются с помощью макросов SAFE и FAST -соответственно: если директива SAFE_FAST не включена, то - SAFE(f) == f && FAST(f) == f_fast, -если включена, то - SAFE(f) == f_safe && FAST(f) == f. -Базовое имя f всегда поддержано и является именем по умолчанию. +нерегулярной. Имя ускоренной редакции: FAST(f). -Директива SAFE_FAST дополнительно используется для нерегулярного ускорения обычных -(одноредакционных) функций. Основное назначение директивы -- анализ падения -производительности при регуляризации. Директиву следует включать только тогда, -когда регулярность библиотеки не имеет значения. +Регулярная и ускоренная редакции функции имеют одинаковый интерфейс и не +отличаются глубиной стека (см. \ref stack.h). -\warning Директива включена вплоть до завершения регуляризации bee2. +Для анализа падения производительности обычных (одноредакционных) функций +предусмотрена директива SAFE_FAST. При включении директивы задействуются +ускоренные редакции фрагментов кода, при невключении -- регулярные. +Директива будет поддерживаться вплоть до завершения регуляризации bee2. + +\warning Директива SAFE_FAST используется исключительно для исследований. +Она не должна включаться при обычной сборке программ. \remark Длины строк, размерности массивов не считаются критическими данными. @@ -75,13 +74,8 @@ extern "C" { ******************************************************************************* */ -#ifdef SAFE_FAST - #define SAFE(tag) tag##_safe - #define FAST(tag) tag -#else - #define SAFE(tag) tag - #define FAST(tag) tag##_fast -#endif +/*! \brief Имя ускоренной редакции функции f */ +#define FAST(f) f##_fast #ifdef __cplusplus } /* extern "C" */ diff --git a/include/bee2/core/stack.h b/include/bee2/core/stack.h index 5c542739..09658de5 100644 --- a/include/bee2/core/stack.h +++ b/include/bee2/core/stack.h @@ -4,7 +4,7 @@ \brief Controlled stack \project bee2 [cryptographic library] \created 2012.05.10 -\version 2025.04.25 +\version 2025.08.09 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -50,27 +50,61 @@ extern "C" { Критические переменные не должны передаваться через обычный стек как параметры функций. +Для корректной работы функций библиотеки на разных аппаратных платформах +указатели на объекты, размещенные в контролируемом стеке, должны быть +выровнены на границу фундаментального блока (см. mem.h). Для этого следует +строить функции по следующей схеме: +1. [Предусловие функции] Указатель stack на контролируемый стек обязательно + выровнен на границу фундаментального блока: + \code + ASSERT(memIsAligned(stack, sizeof(mem_align_t))); + \endcode +2. [Разметка стека в функции] Фрагменты памяти для объектов стека выделяются + с помощью функций memSlice() или memSlice2(). Эти функции гарантируют + выравнивание фрагментов на границу фундаментального блока. +3. [Смещение границы стека] Последним фрагментом памяти при разметке stack + может быть стек для подчиненных функций. Указатель на этот фрагмент можно + получать по адресу &stack, смещая тем самым границу стека. + Пример работы с контролируемым стеком и критической переменной: \code void f2(octet a[], size_t n, octet b[], size_t m, void* stack) { register word sensitive; - octet* tmp1 = (octet*)stack; - octet* tmp2 = tmp1 + 2 * n; - stack = tmp2 + m; + octet* var1; // [n] + word* var2; // [m] + memSlice(stack, + n, O_OF_W(m), SIZE_0, SIZE_MAX, + &var1, &var2, &stack); ... - sensitive = f1(tmp1, 2 * n, stack); + sensitive = f1(var1, 2 * n, stack); ... sensitive = 0; } \endcode +В этом примере функция memSlice2() размечает контролируемый стек stack: +- выделяет в стеке переменные var1 и var2; +- смещает stack, делая его указателем на стек подчиненной функции f1. +. +После разметки выравнивание stack на границу фундаментального блока +сохраняется. + Определение функции f, которая использует контролируемый стек, должно сопровождаться определением функции f_deep, которая определяет максимальную глубину стека f. Функция f_deep берет на вход произвольное число аргументов типа size_t (размерностей) или других типов и возвращает глубину стека в октетах. +Пример (продолжение предыдущего): +\code + size_t f2_deep(size_t n, size_t m) + { + return memSliceSize( + n, O_OF_W(m), f1_deep(n), SIZE_MAX); + } +\endcode + Значение f_deep не должно уменьшаться при увеличении любого ее аргумента. В описании функции f, использующей вспомогательный стек, должен быть diff --git a/include/bee2/core/u16.h b/include/bee2/core/u16.h index 55bfd85a..afa8c424 100644 --- a/include/bee2/core/u16.h +++ b/include/bee2/core/u16.h @@ -4,7 +4,7 @@ \brief 16-bit words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -111,7 +111,7 @@ size_t u16CTZ( register u16 w /*!< [in] слово */ ); -size_t SAFE(u16CTZ)(register u16 w); +size_t u16CTZ(register u16 w); size_t FAST(u16CTZ)(register u16 w); /*! \brief Число старших нулевых битов @@ -125,7 +125,6 @@ size_t u16CLZ( register u16 w /*!< [in] слово */ ); -size_t SAFE(u16CLZ)(register u16 w); size_t FAST(u16CLZ)(register u16 w); /*! \brief Тасование битов diff --git a/include/bee2/core/u32.h b/include/bee2/core/u32.h index 8e427c5a..5cd26461 100644 --- a/include/bee2/core/u32.h +++ b/include/bee2/core/u32.h @@ -4,7 +4,7 @@ \brief 32-bit words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -112,7 +112,6 @@ size_t u32CTZ( register u32 w /*!< [in] слово */ ); -size_t SAFE(u32CTZ)(register u32 w); size_t FAST(u32CTZ)(register u32 w); /*! \brief Число старших нулевых битов @@ -126,7 +125,6 @@ size_t u32CLZ( register u32 w /*!< [in] слово */ ); -size_t SAFE(u32CLZ)(register u32 w); size_t FAST(u32CLZ)(register u32 w); /*! \brief Тасование битов diff --git a/include/bee2/core/u64.h b/include/bee2/core/u64.h index 75fca981..32c22fb6 100644 --- a/include/bee2/core/u64.h +++ b/include/bee2/core/u64.h @@ -4,7 +4,7 @@ \brief 64-bit words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -123,7 +123,6 @@ size_t u64CTZ( register u64 w /*!< [in] слово */ ); -size_t SAFE(u64CTZ)(register u64 w); size_t FAST(u64CTZ)(register u64 w); /*! \brief Число старших нулевых битов @@ -137,7 +136,6 @@ size_t u64CLZ( register u64 w /*!< [in] слово */ ); -size_t SAFE(u64CLZ)(register u64 w); size_t FAST(u64CLZ)(register u64 w); /*! \brief Тасование битов diff --git a/include/bee2/core/util.h b/include/bee2/core/util.h index f3a00670..0f468fce 100644 --- a/include/bee2/core/util.h +++ b/include/bee2/core/util.h @@ -4,7 +4,7 @@ \brief Utilities \project bee2 [cryptographic library] \created 2012.07.16 -\version 2025.06.10 +\version 2025.09.05 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -212,6 +212,25 @@ size_t utilMax( ... /*!< [in] числа */ ); + +/* +******************************************************************************* +Выравнивание +******************************************************************************* +*/ + +/*! \brief Ближайшее сверху кратное + + Определяется ближайшее к size сверху число, кратное alignment. + \return Искомое число. + \remark Функция используется при выравнивании фрагментов памяти на границы + блоков из alignment октетов. +*/ +size_t utilAlign( + size_t size, /*!< [in] размер */ + size_t alignment /*!< [in] кратность */ +); + /* ******************************************************************************* Контрольные суммы diff --git a/include/bee2/core/word.h b/include/bee2/core/word.h index 7a9aafa1..9cbd2adb 100644 --- a/include/bee2/core/word.h +++ b/include/bee2/core/word.h @@ -4,7 +4,7 @@ \brief Machine words \project bee2 [cryptographic library] \created 2014.07.18 -\version 2025.04.25 +\version 2025.08.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -41,8 +41,8 @@ extern "C" { #define WORD_MAX ((word)(WORD_0 - WORD_1)) #define WORD_BIT_POS(pos) (WORD_1 << (pos)) -#define WORD_BIT_HI WORD_BIT_POS(B_PER_W - 1) -#define WORD_BIT_HALF WORD_BIT_POS(B_PER_W / 2) +#define WORD_HI WORD_BIT_POS(B_PER_W - 1) +#define WORD_MID WORD_BIT_POS(B_PER_W / 2) #if (B_PER_W == 16) #include "bee2/core/u16.h" @@ -54,13 +54,8 @@ extern "C" { #define wordParity u16Parity #define wordCTZ u16CTZ #define wordCLZ u16CLZ - #ifdef SAFE_FAST - #define wordCTZ_safe u16CTZ_safe - #define wordCLZ_safe u16CLZ_safe - #else - #define wordCTZ_fast u16CTZ_fast - #define wordCLZ_fast u16CLZ_fast - #endif + #define wordCTZ_fast u16CTZ_fast + #define wordCLZ_fast u16CLZ_fast #define wordShuffle u16Shuffle #define wordDeshuffle u16Deshuffle #define wordNegInv u16NegInv @@ -74,13 +69,8 @@ extern "C" { #define wordParity u32Parity #define wordCTZ u32CTZ #define wordCLZ u32CLZ - #ifdef SAFE_FAST - #define wordCTZ_safe u32CTZ_safe - #define wordCLZ_safe u32CLZ_safe - #else - #define wordCTZ_fast u32CTZ_fast - #define wordCLZ_fast u32CLZ_fast - #endif + #define wordCTZ_fast u32CTZ_fast + #define wordCLZ_fast u32CLZ_fast #define wordShuffle u32Shuffle #define wordDeshuffle u32Deshuffle #define wordNegInv u32NegInv @@ -94,13 +84,8 @@ extern "C" { #define wordParity u64Parity #define wordCTZ u64CTZ #define wordCLZ u64CLZ - #ifdef SAFE_FAST - #define wordCTZ_safe u64CTZ_safe - #define wordCLZ_safe u64CLZ_safe - #else - #define wordCTZ_fast u64CTZ_fast - #define wordCLZ_fast u64CLZ_fast - #endif + #define wordCTZ_fast u64CTZ_fast + #define wordCLZ_fast u64CLZ_fast #define wordShuffle u64Shuffle #define wordDeshuffle u64Deshuffle #define wordNegInv u64NegInv diff --git a/include/bee2/crypto/bake.h b/include/bee2/crypto/bake.h index 710a3827..67aa9207 100644 --- a/include/bee2/crypto/bake.h +++ b/include/bee2/crypto/bake.h @@ -40,7 +40,7 @@ extern "C" { Долговременные параметры bake повторяют долговременные параметры bign и задаются структурой типа bign_params, описанной в заголовочном файле bign.h. Стандартные долговременные параметры можно получить с помощью функции -bignParamsStd(), проверить --- с помощью функции bignValParams(). +bignParamsStd(), проверить --- с помощью функции bignParamsVal(). На личные и открытые ключи распространяются соглашения bign. Генерацию пары ключей можно выполнить с помощью функции bignKeypairGen(), diff --git a/include/bee2/crypto/belt.h b/include/bee2/crypto/belt.h index bd2f6289..4545fa12 100644 --- a/include/bee2/crypto/belt.h +++ b/include/bee2/crypto/belt.h @@ -188,6 +188,7 @@ void beltKeyExpand2( Выполняется зашифрование блока данных block на форматированном ключе key. Результат зашифрования возвращается по адресу block. + \pre memIsAligned(block, 4) == TRUE. */ void beltBlockEncr( octet block[16], /*!< [in,out] блок */ @@ -223,6 +224,7 @@ void beltBlockEncr3( Выполняется расшифрование блока данных block на форматированном ключе key. Результат расшифрования возвращается по адресу block. + \pre memIsAligned(block, 4) == TRUE. */ void beltBlockDecr( octet block[16], /*!< [in,out] блок */ diff --git a/include/bee2/crypto/bign96.h b/include/bee2/crypto/bign96.h index 94859f77..faccf398 100644 --- a/include/bee2/crypto/bign96.h +++ b/include/bee2/crypto/bign96.h @@ -1,10 +1,10 @@ /* ******************************************************************************* \file bign96.h -\brief Experimental Bign level 96 signatures +\brief Experimental Bign signatures of security level 96 \project bee2 [cryptographic library] \created 2021.01.20 -\version 2023.09.22 +\version 2025.09.05 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* diff --git a/include/bee2/defs.h b/include/bee2/defs.h index c63dfaa4..b1de9357 100644 --- a/include/bee2/defs.h +++ b/include/bee2/defs.h @@ -4,7 +4,7 @@ \brief Basic definitions \project bee2 [cryptographic library] \created 2012.04.01 -\version 2025.06.09 +\version 2025.09.05 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -404,6 +404,8 @@ T == octet. #error "Unsupported size_t size" #endif +#define SIZE_HI (SIZE_1 << (B_PER_S - 1)) + /* ******************************************************************************* Макросы конвертации @@ -411,22 +413,22 @@ T == octet. */ /*! \brief Число октетов для размещения nb битов */ -#define O_OF_B(nb) (((nb) + 7) / 8) +#define O_OF_B(nb) ((size_t)(((nb) + 7) / 8)) /*! \brief Число машинных слов для размещения nb битов */ -#define W_OF_B(nb) (((nb) + B_PER_W - 1) / B_PER_W) +#define W_OF_B(nb) ((size_t)(((nb) + B_PER_W - 1) / B_PER_W)) /*! \brief Число битов для размещения no октетов */ -#define B_OF_O(no) ((no) * 8) +#define B_OF_O(no) ((size_t)((no) * 8)) /*! \brief Число машинных слов для размещения no октетов */ -#define W_OF_O(no) (((no) + O_PER_W - 1) / O_PER_W) +#define W_OF_O(no) ((size_t)(((no) + O_PER_W - 1) / O_PER_W)) /*! \brief Число октетов для размещения nw машинных слов */ -#define O_OF_W(nw) ((nw) * O_PER_W) +#define O_OF_W(nw) ((size_t)((nw) * O_PER_W)) /*! \brief Число битов для размещения nw машинных слов */ -#define B_OF_W(nw) ((nw) * B_PER_W) +#define B_OF_W(nw) ((size_t)((nw) * B_PER_W)) /* ******************************************************************************* @@ -478,7 +480,7 @@ typedef u32 err_t; ******************************************************************************* */ -#define B_PER_IMPOSSIBLE 64 +#define B_PER_IMPOSSIBLE ((size_t)64) /*! ******************************************************************************* diff --git a/include/bee2/info.h b/include/bee2/info.h index a3f8dda4..265f4b6e 100644 --- a/include/bee2/info.h +++ b/include/bee2/info.h @@ -4,7 +4,7 @@ \brief Common info \project bee2 [cryptographic library] \created 2012.04.01 -\version 2023.02.12 +\version 2025.08.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -22,21 +22,18 @@ #define __BEE2_INFO #define BEE2_NAME "Bee2" +#define BEE2_VERSION "2.1.9" #define BEE2_VERSION_MAJOR "2" #define BEE2_VERSION_MINOR "1" -#define BEE2_VERSION_PATCH "8" - -#define BEE2_VERSION\ - BEE2_VERSION_MAJOR "." BEE2_VERSION_MINOR "." BEE2_VERSION_PATCH - +#define BEE2_VERSION_PATCH "9" #define BEE2_VERSION_NUM\ - 2, 1, 8 + 2, 1, 9 /*! ******************************************************************************* \mainpage Библиотека Bee2 -\version 2.1.8 +\version 2.1.9 \section toc Содержание @@ -94,7 +91,6 @@ mkdir build cd build cmake [-DCMAKE_BUILD_TYPE={Release|Debug|Coverage|ASan|ASanDbg|MemSan|MemSanDbg|Check}]\ - [-DBUILD_FAST=ON]\ [-DBASH_PLATFORM={BASH_32|BASH_64|BASH_AVX2|BASH_AVX512|BASH_NEON}] .. \endverbatim diff --git a/include/bee2/info.h.in b/include/bee2/info.h.in index 607e0917..5c3e90d2 100644 --- a/include/bee2/info.h.in +++ b/include/bee2/info.h.in @@ -4,7 +4,7 @@ \brief Common info \project bee2 [cryptographic library] \created 2012.04.01 -\version 2023.02.12 +\version 2025.08.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -22,21 +22,18 @@ #define __BEE2_INFO #define BEE2_NAME "Bee2" +#define BEE2_VERSION "@BEE2_VERSION@" #define BEE2_VERSION_MAJOR "@BEE2_VERSION_MAJOR@" #define BEE2_VERSION_MINOR "@BEE2_VERSION_MINOR@" #define BEE2_VERSION_PATCH "@BEE2_VERSION_PATCH@" - -#define BEE2_VERSION\ - BEE2_VERSION_MAJOR "." BEE2_VERSION_MINOR "." BEE2_VERSION_PATCH - #define BEE2_VERSION_NUM\ - @BEE2_VERSION_MAJOR@, @BEE2_VERSION_MINOR@, @BEE2_VERSION_PATCH@ + @BEE2_VERSION_MAJOR@, @BEE2_VERSION_MINOR@, @BEE2_VERSION_PATCH@ /*! ******************************************************************************* \mainpage Библиотека Bee2 -\version @BEE2_VERSION_MAJOR@.@BEE2_VERSION_MINOR@.@BEE2_VERSION_PATCH@ +\version @BEE2_VERSION@ \section toc Содержание @@ -94,7 +91,6 @@ mkdir build cd build cmake [-DCMAKE_BUILD_TYPE={Release|Debug|Coverage|ASan|ASanDbg|MemSan|MemSanDbg|Check}]\ - [-DBUILD_FAST=ON]\ [-DBASH_PLATFORM={BASH_32|BASH_64|BASH_AVX2|BASH_AVX512|BASH_NEON}] .. \endverbatim diff --git a/include/bee2/math/ec.h b/include/bee2/math/ec.h index 349482d4..e710e4df 100644 --- a/include/bee2/math/ec.h +++ b/include/bee2/math/ec.h @@ -4,7 +4,7 @@ \brief Elliptic curves \project bee2 [cryptographic library] \created 2012.04.19 -\version 2023.03.30 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -134,7 +134,7 @@ ec->order задается 2 * ec->f->n + 1 машинным словом. Ко В функцию ecCreate() могут не передаваться параметры base, order и cofactor, определяющие строение группы точек, хотя буферы для base и order могут подготавливаться в ecCreate(). Параметры могут устанавливаться позднее -с помощью функции ecCreateGroup(). +с помощью функции ecGroupCreate(). \pre Все указатели действительны. @@ -383,7 +383,7 @@ typedef struct ec_o ec_dbla_i dbla; /*!< функция удвоения аффинной точки */ ec_tpl_i tpl; /*!< функция утроения */ size_t deep; /*!< максимальная глубина стека функций */ - octet descr[]; /*!< память для размещения данных */ + mem_align_t descr[]; /*!< память для размещения данных */ } ec_o; /* @@ -507,9 +507,9 @@ bool_t ecIsOperable2( \remark Любой из указателей xbase, ybase может быть нулевым. При нулевом указателе соответствующая координата базовой точки устанавливается равной нулю. - \deep{stack} ecCreateGroup_deep(f_deep). + \deep{stack} ecGroupCreate_deep(f_deep). */ -bool_t ecCreateGroup( +bool_t ecGroupCreate( ec_o* ec, /*!< [in,out] описание кривой */ const octet xbase[], /*!< [in] x-координата базовой точки */ const octet ybase[], /*!< [in] y-координата базовой точки */ @@ -519,7 +519,7 @@ bool_t ecCreateGroup( void* stack /*!< [in] вспомогательная память */ ); -size_t ecCreateGroup_deep(size_t f_deep); +size_t ecGroupCreate_deep(size_t f_deep); /*! \brief Группа точек эллиптической кривой работоспособна? @@ -532,7 +532,7 @@ size_t ecCreateGroup_deep(size_t f_deep); \pre Описание ec работоспособно. \return Признак корректности. */ -bool_t ecIsOperableGroup( +bool_t ecGroupIsOperable( const ec_o* ec /*!< [in] описание кривой */ ); diff --git a/include/bee2/math/ec2.h b/include/bee2/math/ec2.h index 746731ea..3f34ff97 100644 --- a/include/bee2/math/ec2.h +++ b/include/bee2/math/ec2.h @@ -4,7 +4,7 @@ \brief Elliptic curves over binary fields \project bee2 [cryptographic library] \created 2012.04.19 -\version 2021.06.30 +\version 2025.09.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -60,7 +60,7 @@ O -- бесконечно удаленная точка. \return Признак успеха. \pre gf2IsOperable(f) == TRUE. \post ec->d == 3. - \post Буферы ec->order и ec->base подготовлены для ecCreateGroup(). + \post Буферы ec->order и ec->base подготовлены для ecGroupCreate(). \keep{ec} ec2CreateLD_keep(f->n). \deep{stack} ec2CreateLD_deep(f->n, f->deep). */ @@ -104,21 +104,21 @@ size_t ec2IsValid_deep(size_t n); Проверяется корректность описания группы точек эллиптической кривой ec. Описание корректно, если: - - ecIsOperableGroup(ec) == TRUE; + - ecGroupIsOperable(ec) == TRUE; - |ec->order * ec->cofactor - (2^m + 1)| <= 2^{m/2 + 1} (границы Хассе); - точка ec->base лежит на ec. . \pre Описание ec работоспособно. \return Признак корректности. \remark Не проверяется, что порядок ec->base равняется ec->order. - \deep{stack} ec2SeemsValidGroup_deep(ec->f->n, ec->f->deep). + \deep{stack} ec2GroupSeemsValid_deep(ec->f->n, ec->f->deep). */ -bool_t ec2SeemsValidGroup( +bool_t ec2GroupSeemsValid( const ec_o* ec, /*!< [in] описание кривой */ void* stack /*!< [in] вспомогательная память */ ); -size_t ec2SeemsValidGroup_deep(size_t n, size_t f_deep); +size_t ec2GroupSeemsValid_deep(size_t n, size_t f_deep); /*! \brief Надежная группа точек эллиптической кривой? @@ -131,15 +131,15 @@ size_t ec2SeemsValidGroup_deep(size_t n, size_t f_deep); \pre Описание ec (включая описание группы точек) работоспособно. \expect Описание ec (включая описание группы точек) корректно. \return Признак успеха проверки. - \deep{stack} ec2IsSafeGroup_deep(ec->f->n). + \deep{stack} ec2GroupIsSafe_deep(ec->f->n). */ -bool_t ec2IsSafeGroup( +bool_t ec2GroupIsSafe( const ec_o* ec, /*!< [in] описание кривой */ size_t mov_threshold, /*!< [in] MOV-порог */ void* stack /*!< [in] вспомогательная память */ ); -size_t ec2IsSafeGroup_deep(size_t n); +size_t ec2GroupIsSafe_deep(size_t n); /* ******************************************************************************* diff --git a/include/bee2/math/ecp.h b/include/bee2/math/ecp.h index daf5ba1d..62f60e65 100644 --- a/include/bee2/math/ecp.h +++ b/include/bee2/math/ecp.h @@ -4,7 +4,7 @@ \brief Elliptic curves over prime fields \project bee2 [cryptographic library] \created 2012.06.24 -\version 2021.06.30 +\version 2025.09.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -61,7 +61,7 @@ O -- бесконечно удаленная точка. \pre gfpIsOperable(f) == TRUE. \expect{FALSE} f->mod > 3. \post ec->d == 3. - \post Буферы ec->order и ec->base подготовлены для ecCreateGroup(). + \post Буферы ec->order и ec->base подготовлены для ecGroupCreate(). \keep{ec} ecpCreateJ_keep(f->n). \deep{stack} ecpCreateJ_deep(f->n, f->deep). */ @@ -106,21 +106,21 @@ size_t ecpIsValid_deep(size_t n, size_t f_deep); Проверяется корректность описания группы точек эллиптической кривой ec. Описание корректно, если: - - ecIsOperableGroup(ec) == TRUE; + - ecGroupIsOperable(ec) == TRUE; - |ec->order * ec->cofactor - (p + 1)| <= 2 * \sqrt(p) (границы Хассе); - точка ec->base лежит на ec. . \pre Описание ec работоспособно. \return Признак корректности. \remark Не проверяется, что порядок ec->base равняется ec->order. - \deep{stack} ecpSeemsValidGroup_deep(ec->f->n, ec->f->deep). + \deep{stack} ecpGroupSeemsValid_deep(ec->f->n, ec->f->deep). */ -bool_t ecpSeemsValidGroup( +bool_t ecpGroupSeemsValid( const ec_o* ec, /*!< [in] описание кривой */ void* stack /*!< [in] вспомогательная память */ ); -size_t ecpSeemsValidGroup_deep(size_t n, size_t f_deep); +size_t ecpGroupSeemsValid_deep(size_t n, size_t f_deep); /*! \brief Надежная группа точек эллиптической кривой? @@ -133,15 +133,15 @@ size_t ecpSeemsValidGroup_deep(size_t n, size_t f_deep); \pre Описание ec (включая описание группы точек) работоспособно. \expect Описание ec (включая описание группы точек) корректно. \return Признак успеха проверки. - \deep{stack} ecpIsSafeGroup_deep(ec->f->n). + \deep{stack} ecpGroupIsSafe_deep(ec->f->n). */ -bool_t ecpIsSafeGroup( +bool_t ecpGroupIsSafe( const ec_o* ec, /*!< [in] описание кривой */ size_t mov_threshold, /*!< [in] MOV-порог */ void* stack /*!< [in] вспомогательная память */ ); -size_t ecpIsSafeGroup_deep(size_t n); +size_t ecpGroupIsSafe_deep(size_t n); /* ******************************************************************************* diff --git a/include/bee2/math/qr.h b/include/bee2/math/qr.h index 0bf36dc1..fbe04e20 100644 --- a/include/bee2/math/qr.h +++ b/include/bee2/math/qr.h @@ -4,7 +4,7 @@ \brief Quotient rings \project bee2 [cryptographic library] \created 2013.08.09 -\version 2015.09.01 +\version 2015.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -21,6 +21,7 @@ #define __BEE2_QR_H #include "bee2/defs.h" +#include "bee2/core/mem.h" #include "bee2/core/obj.h" #ifdef __cplusplus @@ -315,25 +316,25 @@ typedef void (*qr_div_i)( */ typedef struct qr_o { - obj_hdr_t hdr; /*!< заголовок */ + obj_hdr_t hdr; /*!< заголовок */ // ptr_table { - word* mod; /*!< модуль */ - word* unity; /*!< мультипликативная единица */ - void* params; /*!< дополнительные параметры */ + word* mod; /*!< модуль */ + word* unity; /*!< мультипликативная единица */ + void* params; /*!< дополнительные параметры */ // } - size_t n; /*!< размерность */ - size_t no; /*!< длина кодового представления */ - qr_from_i from; /*!< функция импорта */ - qr_to_i to; /*!< функция экспорта */ - qr_add_i add; /*!< функция сложения */ - qr_sub_i sub; /*!< функция вычитания */ - qr_neg_i neg; /*!< функция аддитивного обращения */ - qr_mul_i mul; /*!< функция умножения */ - qr_sqr_i sqr; /*!< функция возведения в квадрат */ - qr_inv_i inv; /*!< функция мультипликативного обращения */ - qr_div_i div; /*!< функция деления */ - size_t deep; /*!< максимальная глубина стека функций */ - octet descr[]; /*!< память для размещения данных */ + size_t n; /*!< размерность */ + size_t no; /*!< длина кодового представления */ + qr_from_i from; /*!< функция импорта */ + qr_to_i to; /*!< функция экспорта */ + qr_add_i add; /*!< функция сложения */ + qr_sub_i sub; /*!< функция вычитания */ + qr_neg_i neg; /*!< функция аддитивного обращения */ + qr_mul_i mul; /*!< функция умножения */ + qr_sqr_i sqr; /*!< функция возведения в квадрат */ + qr_inv_i inv; /*!< функция мультипликативного обращения */ + qr_div_i div; /*!< функция деления */ + size_t deep; /*!< максимальная глубина стека функций */ + mem_align_t descr[]; /*!< память для размещения данных */ } qr_o; /* diff --git a/include/bee2/math/ww.h b/include/bee2/math/ww.h index 24edaa57..eba87f81 100644 --- a/include/bee2/math/ww.h +++ b/include/bee2/math/ww.h @@ -4,7 +4,7 @@ \brief Arbitrary length words \project bee2 [cryptographic library] \created 2012.04.18 -\version 2025.05.07 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -75,18 +75,21 @@ extern "C" { #error "Unsupported word size" #endif /* B_PER_W */ - /*! Корректное слово [n]a? */ -#define wwIsValid(a, n) memIsValid((a), O_OF_W(n)) +#define wwIsValid(a, n)\ + (memIsValid((a), O_OF_W(n)) && memIsAligned((a), O_PER_W)) /*! Буферы слов [n]a и [n]b не пересекаются? */ -#define wwIsDisjoint(a, b, n) memIsDisjoint(a, b, O_OF_W(n)) +#define wwIsDisjoint(a, b, n)\ + memIsDisjoint(a, b, O_OF_W(n)) /*! Буферы слов [n]a и [n]b совпадают или не пересекаются? */ -#define wwIsSameOrDisjoint(a, b, n) memIsSameOrDisjoint(a, b, O_OF_W(n)) +#define wwIsSameOrDisjoint(a, b, n)\ + memIsSameOrDisjoint(a, b, O_OF_W(n)) /*! Буферы слов [n]a и [m]b не пересекаются? */ -#define wwIsDisjoint2(a, n, b, m) memIsDisjoint2(a, O_OF_W(n), b, O_OF_W(m)) +#define wwIsDisjoint2(a, n, b, m)\ + memIsDisjoint2(a, O_OF_W(n), b, O_OF_W(m)) /*! Буферы слов [n]a, [m]b и [k]c не пересекаются? */ #define wwIsDisjoint3(a, n, b, m, c, k)\ @@ -138,7 +141,6 @@ bool_t wwEq( size_t n /*!< [in] длина a и b в машинных словах */ ); -bool_t SAFE(wwEq)(const word a[], const word b[], size_t n); bool_t FAST(wwEq)(const word a[], const word b[], size_t n); /*! \brief Сравнение слов @@ -154,7 +156,6 @@ int wwCmp( size_t n /*!< [in] длина a и b в машинных словах */ ); -int SAFE(wwCmp)(const word a[], const word b[], size_t n); int FAST(wwCmp)(const word a[], const word b[], size_t n); /*! \brief Сравнение слов разной длины @@ -171,7 +172,6 @@ int wwCmp2( size_t m /*!< [in] длина b в машинных словах */ ); -int SAFE(wwCmp2)(const word a[], size_t n, const word b[], size_t m); int FAST(wwCmp2)(const word a[], size_t n, const word b[], size_t m); /*! \brief Сравнение слова c машинным словом @@ -186,7 +186,6 @@ int wwCmpW( register word w /*!< [in] машинное слово */ ); -int SAFE(wwCmpW)(const word a[], size_t n, register word w); int FAST(wwCmpW)(const word a[], size_t n, register word w); /*! \brief Cложение слов по модулю 2 @@ -270,7 +269,6 @@ bool_t wwIsZero( size_t n /*!< [in] длина a в машинных словах */ ); -bool_t SAFE(wwIsZero)(const word a[], size_t n); bool_t FAST(wwIsZero)(const word a[], size_t n); /*! \brief Принимает значение -- машинное слово? @@ -290,7 +288,6 @@ bool_t wwIsW( register word w /*!< [in] значение */ ); -bool_t SAFE(wwIsW)(const word a[], size_t n, register word w); bool_t FAST(wwIsW)(const word a[], size_t n, register word w); /*! \brief Повтор машинного слова? @@ -309,7 +306,6 @@ bool_t wwIsRepW( register word w /*!< [in] значение */ ); -bool_t SAFE(wwIsRepW)(const word a[], size_t n, register word w); bool_t FAST(wwIsRepW)(const word a[], size_t n, register word w); /*! \brief Размер значащей части слова в машинных словах diff --git a/include/bee2/math/zm.h b/include/bee2/math/zm.h index d5c563fc..3f563a43 100644 --- a/include/bee2/math/zm.h +++ b/include/bee2/math/zm.h @@ -4,7 +4,7 @@ \brief Quotient rings of integers modulo m \project bee2 [cryptographic library] \created 2013.09.14 -\version 2023.02.02 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -86,18 +86,18 @@ c <- a * b * R^{-1} \mod mod, кольца Z / (mod). При вычислениях в кольце используется обычная редукция. \pre no > 0 && mod[no - 1] > 0. \post r->no == no и r->n == W_OF_O(no). - \keep{r} zmCreatePlain_keep(no). - \deep{stack} zmCreatePlain_deep(no). + \keep{r} zmPlainCreate_keep(no). + \deep{stack} zmPlainCreate_deep(no). */ -void zmCreatePlain( +void zmPlainCreate( qr_o* r, /*!< [out] описание кольца */ const octet mod[], /*!< [in] модуль */ size_t no, /*!< [in] длина mod в октетах */ void* stack /*!< [in] вспомогательная память */ ); -size_t zmCreatePlain_keep(size_t no); -size_t zmCreatePlain_deep(size_t no); +size_t zmPlainCreate_keep(size_t no); +size_t zmPlainCreate_deep(size_t no); /*! \brief Создание описания кольца вычетов целых чисел с редукцией Крэндалла diff --git a/include/bee2/math/zz.h b/include/bee2/math/zz.h index 95a72303..f61480da 100644 --- a/include/bee2/math/zz.h +++ b/include/bee2/math/zz.h @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers \project bee2 [cryptographic library] \created 2012.04.22 -\version 2023.09.23 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -194,8 +194,6 @@ bool_t zzIsSumEq( size_t n /*!< [in] длина a, b, c в машинных словах */ ); -bool_t SAFE(zzIsSumEq)(const word c[], const word a[], const word b[], - size_t n); bool_t FAST(zzIsSumEq)(const word c[], const word a[], const word b[], size_t n); @@ -215,8 +213,6 @@ bool_t zzIsSumWEq( register word w /*!< [in] второе слагаемое */ ); -bool_t SAFE(zzIsSumWEq)(const word b[], const word a[], size_t n, - register word w); bool_t FAST(zzIsSumWEq)(const word b[], const word a[], size_t n, register word w); @@ -667,8 +663,6 @@ void zzAddMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzAddMod)(word c[], const word a[], const word b[], const word mod[], - size_t n); void FAST(zzAddMod)(word c[], const word a[], const word b[], const word mod[], size_t n); @@ -691,8 +685,6 @@ void zzAddWMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzAddWMod)(word b[], const word a[], register word w, - const word mod[], size_t n); void FAST(zzAddWMod)(word b[], const word a[], register word w, const word mod[], size_t n); @@ -716,8 +708,6 @@ void zzSubMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzSubMod)(word c[], const word a[], const word b[], - const word mod[], size_t n); void FAST(zzSubMod)(word c[], const word a[], const word b[], const word mod[], size_t n); @@ -740,8 +730,6 @@ void zzSubWMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzSubWMod)(word b[], const word a[], register word w, - const word mod[], size_t n); void FAST(zzSubWMod)(word b[], const word a[], register word w, const word mod[], size_t n); @@ -764,7 +752,6 @@ void zzNegMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzNegMod)(word b[], const word a[], const word mod[], size_t n); void FAST(zzNegMod)(word b[], const word a[], const word mod[], size_t n); /*! \brief Умножение чисел по модулю @@ -897,7 +884,6 @@ void zzDoubleMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n); void FAST(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n); /*! \brief Половина числа по модулю @@ -919,7 +905,6 @@ void zzHalfMod( size_t n /*!< [in] длина чисел в машинных словах */ ); -void SAFE(zzHalfMod)(word b[], const word a[], const word mod[], size_t n); void FAST(zzHalfMod)(word b[], const word a[], const word mod[], size_t n); /*! \brief Почти-обращение по модулю @@ -1058,7 +1043,6 @@ void zzRedCrand( void* stack /*!< [in] вспомогательная память (не исп.) */ ); -void SAFE(zzRedCrand)(word a[], const word mod[], size_t n, void* stack); void FAST(zzRedCrand)(word a[], const word mod[], size_t n, void* stack); size_t zzRedCrand_deep(size_t n); @@ -1101,8 +1085,6 @@ void zzRedBarr( void* stack /*!< [in] вспомогательная память */ ); -void SAFE(zzRedBarr)(word a[], const word mod[], size_t n, - const word barr_param[], void* stack); void FAST(zzRedBarr)(word a[], const word mod[], size_t n, const word barr_param[], void* stack); @@ -1134,8 +1116,6 @@ void zzRedMont( void* stack /*!< [in] вспомогательная память */ ); -void SAFE(zzRedMont)(word a[], const word mod[], size_t n, - register word mont_param, void* stack); void FAST(zzRedMont)(word a[], const word mod[], size_t n, register word mont_param, void* stack); @@ -1164,8 +1144,6 @@ void zzRedCrandMont( void* stack /*!< [in] вспомогательная память */ ); -void SAFE(zzRedCrandMont)(word a[], const word mod[], size_t n, - register word mont_param, void* stack); void FAST(zzRedCrandMont)(word a[], const word mod[], size_t n, register word mont_param, void* stack); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8cc031d..17faa6da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,10 @@ set(src core/u64.c core/util.c core/word.c - crypto/bake.c + crypto/bake/bake_bmqv.c + crypto/bake/bake_bsts.c + crypto/bake/bake_bpace.c + crypto/bake/bake_misc.c crypto/bash/bash_f.c crypto/bash/bash_hash.c crypto/bash/bash_prg.c @@ -45,9 +48,9 @@ set(src crypto/belt/belt_kwp.c crypto/belt/belt_mac.c crypto/belt/belt_pbkdf.c + crypto/bign/bign_ec.c crypto/bign/bign_ibs.c crypto/bign/bign_keyt.c - crypto/bign/bign_lcl.c crypto/bign/bign_misc.c crypto/bign/bign_params.c crypto/bign/bign_sign.c @@ -99,7 +102,7 @@ set_property(TARGET bee2_static PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC}) install(TARGETS bee2_static - DESTINATION ${LIB_INSTALL_DIR} + DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) @@ -124,7 +127,7 @@ if(BUILD_SHARED_LIBS) set_target_properties(bee2 PROPERTIES VERSION ${BEE2_VERSION} SOVERSION 2.0) install(TARGETS bee2 - DESTINATION ${LIB_INSTALL_DIR} + DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() diff --git a/src/core/blob.c b/src/core/blob.c index 75f65f6f..aa3b6f1b 100644 --- a/src/core/blob.c +++ b/src/core/blob.c @@ -4,27 +4,29 @@ \brief Blobs \project bee2 [cryptographic library] \created 2012.04.01 -\version 2023.03.23 +\version 2025.09.12 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ +#include #include "bee2/core/blob.h" #include "bee2/core/mem.h" #include "bee2/core/util.h" /* ******************************************************************************* -Блоб: реализация +Создание / изменение размера В куче выделяется память под указатель ptr. Память выделяется страницами. -Первые sizeof(size_t) октетов по адресу ptr --- размер блоба, -следующие октеты --- собственно блоб. +Первые sizeof(mem_align_t) октетов по адресу ptr --- заголовок блоба, +следующие за заголовком октеты --- собственно блоб. В заголовке указывается +длина блоба. Длина заголовка выбрана так, чтобы блоб был выровнен на границу +фундаментального блока. \todo Обеспечить защиту памяти блоба от утечек. - \todo Полноценная проверка корректности блоба. ******************************************************************************* */ @@ -34,63 +36,45 @@ // требуется страниц #define blobPageCount(size)\ - (((size) + sizeof(size_t) + BLOB_PAGE_SIZE - 1) / BLOB_PAGE_SIZE) + (((size) + sizeof(mem_align_t) + BLOB_PAGE_SIZE - 1) / BLOB_PAGE_SIZE) // требуется памяти на страницах #define blobActualSize(size)\ (blobPageCount(size) * BLOB_PAGE_SIZE) -// heap-указатель для блоба -#define blobPtrOf(blob) ((size_t*)blob - 1) +// заголовок блоба +#define blobHdrOf(blob) ((mem_align_t*)(blob) - 1) + +// heap-указатель блоба +#define blobPtrOf(blob) ((void*)blobHdrOf(blob)) // размер блоба -#define blobSizeOf(blob) (*blobPtrOf(blob)) +#define blobSizeOf(blob) (blobHdrOf(blob)->s) // страничный размер блоба #define blobActualSizeOf(blob) (blobActualSize(blobSizeOf(blob))) -// блоб для heap-указателя -#define blobValueOf(ptr) ((blob_t)((size_t*)ptr + 1)) +// блоб по heap-указателю +#define blobValueOf(ptr) ((blob_t)((mem_align_t*)(ptr) + 1)) blob_t blobCreate(size_t size) { - size_t* ptr; + void* ptr; if (size == 0) return 0; - ptr = (size_t*)memAlloc(blobActualSize(size)); + ptr = memAlloc(blobActualSize(size)); if (ptr == 0) return 0; - *ptr = size; + ASSERT(memIsAligned(ptr, sizeof(mem_align_t))); + ((mem_align_t*)ptr)->s = size; memSetZero(blobValueOf(ptr), size); return blobValueOf(ptr); } -bool_t blobIsValid(const blob_t blob) -{ - return blob == 0 || memIsValid(blobPtrOf(blob), blobActualSizeOf(blob)); -} - -void blobWipe(blob_t blob) -{ - ASSERT(blobIsValid(blob)); - if (blob != 0) - memWipe(blob, blobSizeOf(blob)); -} - -void blobClose(blob_t blob) -{ - ASSERT(blobIsValid(blob)); - if (blob) - { - memWipe(blobPtrOf(blob), blobActualSizeOf(blob)); - memFree(blobPtrOf(blob)); - } -} - blob_t blobResize(blob_t blob, size_t size) { size_t old_size; - size_t* ptr; + void* ptr; // pre ASSERT(blobIsValid(blob)); // создать блоб @@ -108,18 +92,77 @@ blob_t blobResize(blob_t blob, size_t size) ptr = blobPtrOf(blob); if (blobActualSizeOf(blob) != blobActualSize(size)) { - ptr = (size_t*)memRealloc(ptr, blobActualSize(size)); + ptr = memRealloc(ptr, blobActualSize(size)); if (ptr == 0) return 0; + ASSERT(memIsAligned(ptr, sizeof(mem_align_t))); } // настроить и возвратить блоб - *ptr = size; + ((mem_align_t*)ptr)->s = size; blob = blobValueOf(ptr); if (size > old_size) memSetZero((octet*)blob + old_size, size - old_size); return blob; } +/* +******************************************************************************* +Создание с разметкой памяти +******************************************************************************* +*/ + +extern size_t memSliceSizeArgs(size_t c1, va_list args); +extern void memSliceArgs(const void* buf, size_t c1, va_list args); + +blob_t blobCreate2(size_t c1, ...) +{ + va_list args; + size_t size; + blob_t blob; + // определить требуемый размер блоба + va_start(args, c1); + size = memSliceSizeArgs(c1, args); + va_end(args); + // создать блоб + blob = blobCreate(size); + // разметить память + if (blob) + { + va_start(args, c1); + memSliceArgs(blob, c1, args); + va_end(args); + } + return blob; +} + +/* +******************************************************************************* +Другие функции +******************************************************************************* +*/ + +bool_t blobIsValid(const blob_t blob) +{ + return blob == 0 || memIsValid(blobPtrOf(blob), blobActualSizeOf(blob)); +} + +void blobWipe(blob_t blob) +{ + ASSERT(blobIsValid(blob)); + if (blob != 0) + memWipe(blob, blobSizeOf(blob)); +} + +void blobClose(blob_t blob) +{ + ASSERT(blobIsValid(blob)); + if (blob) + { + memWipe(blobPtrOf(blob), blobActualSizeOf(blob)); + memFree(blobPtrOf(blob)); + } +} + size_t blobSize(const blob_t blob) { ASSERT(blobIsValid(blob)); diff --git a/src/core/hex.c b/src/core/hex.c index babbe1a1..52e1fa7d 100644 --- a/src/core/hex.c +++ b/src/core/hex.c @@ -4,7 +4,7 @@ \brief Hexadecimal strings \project bee2 [cryptographic library] \created 2015.10.29 -\version 2025.06.10 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -125,7 +125,7 @@ void hexLower(char* hex) ******************************************************************************* */ -bool_t SAFE(hexEq2)(const void* buf, const char* hex, size_t len) +bool_t hexEq2(const void* buf, const char* hex, size_t len) { register word diff = 0; ASSERT(hexIsValid2(hex, len)); @@ -145,10 +145,10 @@ bool_t FAST(hexEq2)(const void* buf, const char* hex, size_t len) return TRUE; } -bool_t SAFE(hexEq)(const void* buf, const char* hex) +bool_t hexEq(const void* buf, const char* hex) { ASSERT(hexIsValid(hex)); - return SAFE(hexEq2)(buf, hex, strLen(hex)); + return hexEq2(buf, hex, strLen(hex)); } bool_t FAST(hexEq)(const void* buf, const char* hex) @@ -157,7 +157,7 @@ bool_t FAST(hexEq)(const void* buf, const char* hex) return FAST(hexEq2)(buf, hex, strLen(hex)); } -bool_t SAFE(hexEqRev2)(const void* buf, const char* hex, size_t len) +bool_t hexEqRev2(const void* buf, const char* hex, size_t len) { register word diff = 0; ASSERT(hexIsValid(hex)); @@ -179,10 +179,10 @@ bool_t FAST(hexEqRev2)(const void* buf, const char* hex, size_t len) return TRUE; } -bool_t SAFE(hexEqRev)(const void* buf, const char* hex) +bool_t hexEqRev(const void* buf, const char* hex) { ASSERT(hexIsValid(hex)); - return SAFE(hexEqRev2)(buf, hex, strLen(hex)); + return hexEqRev2(buf, hex, strLen(hex)); } bool_t FAST(hexEqRev)(const void* buf, const char* hex) diff --git a/src/core/mem.c b/src/core/mem.c index 7f85ff77..92e4b96e 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -4,7 +4,7 @@ \brief Memory management \project bee2 [cryptographic library] \created 2012.12.18 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -23,6 +23,7 @@ #include #endif #endif +#include #include "bee2/core/mem.h" #include "bee2/core/util.h" @@ -41,9 +42,29 @@ bool_t memIsValid(const void* buf, size_t count) return count == 0 || buf != 0; } -bool_t memIsAligned(const void* buf, size_t size) +/* +******************************************************************************* +Выравнивание + +\remark В первых редакциях модуля (вплоть до 2025-09-22) буферы памяти +по возможности обрабатывались как массивы машинных слов (word). При этом +не учитывалось выравнивание буферов на границу машшинного слова. Чтобы учесть +выравнивание, нужно либо +a) перейти к работе с буферами как массивами октетов, либо +b) усложнять функции, придавая им довольно громоздкую форму. + +Был выбран вариант a). Для быстрой работы с массивами машинных слов можно +переключиться на функции модуля ww. +******************************************************************************* +*/ + +#ifndef UINTPTR_MAX +typedef size_t uintptr_t; +#endif + +bool_t memIsAligned(const void* buf, size_t alignment) { - return (size_t)buf % size == 0; + return (uintptr_t)buf % alignment == 0; } /* @@ -84,11 +105,6 @@ void memSet(void* buf, octet c, size_t count) void memNeg(void* buf, size_t count) { ASSERT(memIsValid(buf, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - *(word*)buf = ~*(word*)buf; - buf = (word*)buf + 1; - } while (count--) { *(octet*)buf = ~*(octet*)buf; @@ -130,47 +146,18 @@ void memFree(void* buf) #endif } + /* ******************************************************************************* -Дополнительные функции - -\remark Функция memWipe() повторяет функцию OPENSSL_cleanse() -из библиотеки OpenSSL: -\code - unsigned char cleanse_ctr = 0; - void OPENSSL_cleanse(void *ptr, size_t len) - { - unsigned char *p = ptr; - size_t loop = len, ctr = cleanse_ctr; - while(loop--) - { - *(p++) = (unsigned char)ctr; - ctr += (17 + ((size_t)p & 0xF)); - } - p=memchr(ptr, (unsigned char)ctr, len); - if(p) - ctr += (63 + (size_t)p); - cleanse_ctr = (unsigned char)ctr; - } -\endcode - -\remark На платформе Windows есть функции SecureZeroMemory() -и RtlSecureZeroMemory(), которые, как и memWipe(), выполняют -гарантированную очистку памяти. +Сравнение буферов памяти ******************************************************************************* */ -bool_t SAFE(memEq)(const void* buf1, const void* buf2, size_t count) +bool_t memEq(const void* buf1, const void* buf2, size_t count) { register word diff = 0; ASSERT(memIsValid(buf1, count)); ASSERT(memIsValid(buf2, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - diff |= *(const word*)buf1 ^ *(const word*)buf2; - buf1 = (const word*)buf1 + 1; - buf2 = (const word*)buf2 + 1; - } while (count--) { diff |= *(const octet*)buf1 ^ *(const octet*)buf2; @@ -187,7 +174,7 @@ bool_t FAST(memEq)(const void* buf1, const void* buf2, size_t count) return memcmp(buf1, buf2, count) == 0; } -int SAFE(memCmp)(const void* buf1, const void* buf2, size_t count) +int memCmp(const void* buf1, const void* buf2, size_t count) { register word less = 0; register word greater = 0; @@ -232,34 +219,28 @@ int FAST(memCmp)(const void* buf1, const void* buf2, size_t count) return 0; } -int SAFE(memCmpRev)(const void* buf1, const void* buf2, size_t count) +int memCmpRev(const void* buf1, const void* buf2, size_t count) { register word less = 0; register word greater = 0; - register word w1; - register word w2; + register word w1 = 0; + register word w2 = 0; + size_t filled = 0; ASSERT(memIsValid(buf1, count)); ASSERT(memIsValid(buf2, count)); - if (count % O_PER_W) + while (count--) { - w1 = w2 = 0; - while (count % O_PER_W) + w1 = w1 << 8 | ((const octet*)buf1)[count]; + w2 = w2 << 8 | ((const octet*)buf2)[count]; + if (++filled == O_PER_W) { - w1 = w1 << 8 | ((const octet*)buf1)[--count]; - w2 = w2 << 8 | ((const octet*)buf2)[count]; + less |= ~greater & wordLess(w1, w2); + greater |= ~less & wordGreater(w1, w2); + filled = 0; } - less |= ~greater & wordLess01(w1, w2); - greater |= ~less & wordGreater01(w1, w2); } - count /= O_PER_W; - while (count--) + if (filled) { - w1 = ((const word*)buf1)[count]; - w2 = ((const word*)buf2)[count]; -#if (OCTET_ORDER == BIG_ENDIAN) - w1 = wordRev(w1); - w2 = wordRev(w2); -#endif less |= ~greater & wordLess(w1, w2); greater |= ~less & wordGreater(w1, w2); } @@ -281,6 +262,36 @@ int FAST(memCmpRev)(const void* buf1, const void* buf2, size_t count) return 0; } +/* +******************************************************************************* +Очистка буфера памяти + +\remark Функция memWipe() повторяет функцию OPENSSL_cleanse() +из библиотеки OpenSSL: +\code + unsigned char cleanse_ctr = 0; + void OPENSSL_cleanse(void *ptr, size_t len) + { + unsigned char *p = ptr; + size_t loop = len, ctr = cleanse_ctr; + while(loop--) + { + *(p++) = (unsigned char)ctr; + ctr += (17 + ((size_t)p & 0xF)); + } + p=memchr(ptr, (unsigned char)ctr, len); + if(p) + ctr += (63 + (size_t)p); + cleanse_ctr = (unsigned char)ctr; + } +\endcode + +\remark На платформе Windows есть функции SecureZeroMemory() +и RtlSecureZeroMemory(), которые, как и memWipe(), выполняют +гарантированную очистку памяти. +******************************************************************************* +*/ + void memWipe(void* buf, size_t count) { static octet wipe_ctr = 0; @@ -297,15 +308,16 @@ void memWipe(void* buf, size_t count) wipe_ctr = (octet)ctr; } -bool_t SAFE(memIsZero)(const void* buf, size_t count) +/* +******************************************************************************* +Другие функции +******************************************************************************* +*/ + +bool_t memIsZero(const void* buf, size_t count) { register word diff = 0; ASSERT(memIsValid(buf, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - diff |= *(const word*)buf; - buf = (const word*)buf + 1; - } while (count--) { diff |= *(const octet*)buf; @@ -317,9 +329,6 @@ bool_t SAFE(memIsZero)(const void* buf, size_t count) bool_t FAST(memIsZero)(const void* buf, size_t count) { ASSERT(memIsValid(buf, count)); - for (; count >= O_PER_W; count -= O_PER_W, buf = (const word*)buf + 1) - if (*(const word*)buf) - return FALSE; for (; count--; buf = (const octet*)buf + 1) if (*(const octet*)buf) return FALSE; @@ -335,7 +344,7 @@ size_t memNonZeroSize(const void* buf, size_t count) return 0; } -bool_t SAFE(memIsRep)(const void* buf, size_t count, octet o) +bool_t memIsRep(const void* buf, size_t count, octet o) { register word diff = 0; ASSERT(memIsValid(buf, count)); @@ -464,13 +473,6 @@ void memXor(void* dest, const void* src1, const void* src2, size_t count) { ASSERT(memIsSameOrDisjoint(src1, dest, count)); ASSERT(memIsSameOrDisjoint(src2, dest, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - *(word*)dest = *(const word*)src1 ^ *(const word*)src2; - src1 = (const word*)src1 + 1; - src2 = (const word*)src2 + 1; - dest = (word*)dest + 1; - } while (count--) { *(octet*)dest = *(const octet*)src1 ^ *(const octet*)src2; @@ -483,12 +485,6 @@ void memXor(void* dest, const void* src1, const void* src2, size_t count) void memXor2(void* dest, const void* src, size_t count) { ASSERT(memIsSameOrDisjoint(src, dest, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - *(word*)dest ^= *(const word*)src; - src = (const word*)src + 1; - dest = (word*)dest + 1; - } while (count--) { *(octet*)dest ^= *(const octet*)src; @@ -500,12 +496,6 @@ void memXor2(void* dest, const void* src, size_t count) void memSwap(void* buf1, void* buf2, size_t count) { ASSERT(memIsDisjoint(buf1, buf2, count)); - for (; count >= O_PER_W; count -= O_PER_W) - { - SWAP(*(word*)buf1, *(word*)buf2); - buf1 = (word*)buf1 + 1; - buf2 = (word*)buf2 + 1; - } while (count--) { SWAP(*(octet*)buf1, *(octet*)buf2); @@ -514,12 +504,6 @@ void memSwap(void* buf1, void* buf2, size_t count) } } -/* -******************************************************************************* -Реверс октетов -******************************************************************************* -*/ - void memRev(void* buf, size_t count) { register size_t i = count / 2; @@ -531,3 +515,107 @@ void memRev(void* buf, size_t count) ((octet*)buf)[i] ^= ((octet*)buf)[count - 1 - i]; } } + +/* +******************************************************************************* +Разметка памяти + +\remark Макрос va_copy поддержан в Visual Studio только в 2013 году. +\remark Неотрицательное целое n является степенью двойки <=> + (n & (n - 1)) == 0. +******************************************************************************* +*/ + +#if defined(_MSC_VER) && (_MSC_VER < 1800) + #define va_copy(dest, src) ((dest) = (src)) +#endif + +#define memSliceSizeof(c)\ + (CASSERT((sizeof(mem_align_t) & (sizeof(mem_align_t) - 1)) == 0),\ + ((c + sizeof(mem_align_t) - 1) & ~(sizeof(mem_align_t) - 1))) + +size_t memSliceSizeArgs(size_t c1, va_list args) +{ + size_t size; + size_t s; + size_t c; + // просмотреть ci + for (size = s = 0, c = c1; c != SIZE_MAX;) + { + if ((c & SIZE_HI) == 0) + { + s = memSliceSizeof(s); + size += s; + s = c; + } + else if ((c &= ~SIZE_HI) > s) + s = c; + c = va_arg(args, size_t); + } + return size + s; +} + +void memSliceArgs(const void* buf, size_t c1, va_list args) +{ + va_list args1; + size_t s; + size_t c; + // pre + ASSERT(memIsAligned(buf, sizeof(mem_align_t))); + // найти p1 + va_copy(args1, args); + for (c = c1; c != SIZE_MAX;) + c = va_arg(args1, size_t); + // просмотреть (ci, pi) + for (s = 0, c = c1; c != SIZE_MAX;) + { + const void** p; + if ((c & SIZE_HI) == 0) + { + s = memSliceSizeof(s); + buf = (const octet*)buf + s; + s = 0; + } + p = va_arg(args1, const void**); + ASSERT(memIsValid(p, sizeof(const void*))); + ASSERT(memIsAligned(buf, sizeof(mem_align_t))); + *p = buf; + if ((c & SIZE_HI) != 0) + { + if ((c &= ~SIZE_HI) > s) + s = c; + } + else + s = c; + c = va_arg(args, size_t); + } + va_end(args1); +} + +size_t memSliceSize(size_t c1, ...) +{ + va_list args; + size_t size; + va_start(args, c1); + size = memSliceSizeArgs(c1, args); + va_end(args); + return size; +} + +void memSlice(const void* buf, size_t c1, ...) +{ + va_list args; + va_start(args, c1); + memSliceArgs(buf, c1, args); + va_end(args); +} + +void* memSliceNext(void* ptr, size_t count) +{ + return (octet*)ptr + memSliceSizeof(count); +} + +const void* memSliceNext2(const void* ptr, size_t count) +{ + return (const octet*)ptr + memSliceSizeof(count); +} diff --git a/src/core/oid.c b/src/core/oid.c index 80059579..fc12a1b4 100644 --- a/src/core/oid.c +++ b/src/core/oid.c @@ -4,7 +4,7 @@ \brief Object identifiers \project bee2 [cryptographic library] \created 2013.02.04 -\version 2025.06.10 +\version 2025.07.31 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -95,7 +95,7 @@ size_t oidFromDER(char* oid, const octet der[], size_t count) { size_t len, c; c = derOIDDec(oid, &len, der, count); - if (len == SIZE_MAX || c != count) + if (c == SIZE_MAX || c != count || len == SIZE_MAX) return SIZE_MAX; return len; } diff --git a/src/core/rng.c b/src/core/rng.c index 75e2a2ec..e5633ec6 100644 --- a/src/core/rng.c +++ b/src/core/rng.c @@ -4,7 +4,7 @@ \brief Entropy sources and random number generators \project bee2 [cryptographic library] \created 2014.10.13 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -34,17 +34,22 @@ bool_t rngTestFIPS1(const octet buf[2500]) { - size_t s = 0; - size_t count = W_OF_O(2500); + register size_t s; + register word w; + size_t count; ASSERT(memIsValid(buf, 2500)); - if (O_OF_W(count) > 2500) + for (w = 0, count = 2500; !memIsAligned(buf, O_PER_W); ++buf, --count) + w = (w << 8) | *buf; + s = wordWeight(w); + for (; count >= O_PER_W; buf += O_PER_W, count -= O_PER_W) { - ASSERT(B_PER_W == 64); - s = u32Weight(*(const u32*)(buf + 2496)); - --count; + ASSERT(memIsAligned(buf, O_PER_W)); + s += wordWeight(*(const word*)buf); } - while (count--) - s += wordWeight(((const word*)buf)[count]); + for (w = 0; count; ++buf, --count) + w = (w << 8) | *buf; + s += wordWeight(w); + CLEAN(w); return 9725 < s && s < 10275; } @@ -263,7 +268,7 @@ static bool_t rngTRNG2IsAvail() static err_t rngTRNGRead(void* buf, size_t* read, size_t count) { - u32* rand = (u32*)buf; + u32 rand; // pre ASSERT(memIsValid(read, O_PER_S)); ASSERT(memIsValid(buf, count)); @@ -271,27 +276,35 @@ static err_t rngTRNGRead(void* buf, size_t* read, size_t count) *read = 0; if (!rngTRNGIsAvail()) return ERR_FILE_NOT_FOUND; - // короткий буфер? - if (count < 4) - return ERR_OK; // генерация - for (; *read + 4 <= count; *read += 4, ++rand) - if (!rngRDStep(rand)) + while (*read + 4 <= count) + { + if (!rngRDStep(&rand)) + { + CLEAN(rand); return ERR_BAD_ENTROPY; + } + memCopy(buf, &rand, 4); + buf = (octet*)buf + 4, *read += 4; + } // неполный блок if (*read < count) { - rand = (u32*)((octet*)buf + count - 4); - if (!rngRDStep(rand)) + if (!rngRDStep(&rand)) + { + CLEAN(rand); return ERR_BAD_ENTROPY; + } + memCopy(buf, &rand, count - *read); *read = count; } + CLEAN(rand); return ERR_OK; } static err_t rngTRNG2Read(void* buf, size_t* read, size_t count) { - u32* rand = (u32*)buf; + u32 rand; // pre ASSERT(memIsValid(read, O_PER_S)); ASSERT(memIsValid(buf, count)); @@ -299,21 +312,29 @@ static err_t rngTRNG2Read(void* buf, size_t* read, size_t count) *read = 0; if (!rngTRNG2IsAvail()) return ERR_FILE_NOT_FOUND; - // короткий буфер? - if (count < 4) - return ERR_OK; // генерация - for (; *read + 4 <= count; *read += 4, ++rand) - if (!rngRDStep2(rand)) + while (*read + 4 <= count) + { + if (!rngRDStep2(&rand)) + { + CLEAN(rand); return ERR_BAD_ENTROPY; + } + memCopy(buf, &rand, 4); + buf = (octet*)buf + 4, *read += 4; + } // неполный блок if (*read < count) { - rand = (u32*)((octet*)buf + count - 4); - if (!rngRDStep2(rand)) + if (!rngRDStep2(&rand)) + { + CLEAN(rand); return ERR_BAD_ENTROPY; + } + memCopy(buf, &rand, count - *read); *read = count; } + CLEAN(rand); return ERR_OK; } @@ -666,7 +687,7 @@ err_t rngESHealth() typedef struct { octet block[32]; /*< дополнительные данные brngCTR */ - octet alg_state[]; /*< [MAX(beltHash_keep(), brngCTR_keep())] */ + mem_align_t alg_state[]; /*< [MAX(beltHash_keep(), brngCTR_keep())] */ } rng_state_st; static size_t _once; /*< триггер однократности */ diff --git a/src/core/u16.c b/src/core/u16.c index e82170a2..edf0172a 100644 --- a/src/core/u16.c +++ b/src/core/u16.c @@ -4,7 +4,7 @@ \brief 16-bit unsigned words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -61,7 +61,7 @@ bool_t u16Parity(register u16 w) return (bool_t)(w & U16_1); } -size_t SAFE(u16CTZ)(register u16 w) +size_t u16CTZ(register u16 w) { return 16 - u16Weight(w | (U16_0 - w)); } @@ -80,7 +80,7 @@ size_t FAST(u16CTZ)(register u16 w) return ((u16)(w << 1)) ? l - 2 : l - (w ? 1 : 0); } -size_t SAFE(u16CLZ)(register u16 w) +size_t u16CLZ(register u16 w) { w = w | w >> 1; w = w | w >> 2; @@ -139,6 +139,7 @@ void u16From(u16 dest[], const void* src, size_t count) { ASSERT(memIsValid(src, count)); ASSERT(memIsValid(dest, count + count % 2)); + ASSERT(memIsAligned(dest, 2)); memMove(dest, src, count); if (count % 2) ((octet*)dest)[count] = 0; @@ -152,15 +153,19 @@ void u16To(void* dest, size_t count, const u16 src[]) { ASSERT(memIsValid(src, count + count % 2)); ASSERT(memIsValid(dest, count)); - memMove(dest, src, count); #if (OCTET_ORDER == BIG_ENDIAN) if (count % 2) { register u16 u = src[--count / 2]; + memMove(dest, src, count); ((octet*)dest)[count] = (octet)u; CLEAN(u); } - for (count /= 2; count--;) - ((u16*)dest)[count] = u16Rev(((u16*)dest)[count]); + else + memMove(dest, src, count); + for (; count; count -= 2) + SWAP(((octet*)dest)[count - 2], ((octet*)dest)[count - 1]); +#else + memMove(dest, src, count); #endif // OCTET_ORDER } diff --git a/src/core/u32.c b/src/core/u32.c index 8402a1f3..267f5ef4 100644 --- a/src/core/u32.c +++ b/src/core/u32.c @@ -4,7 +4,7 @@ \brief 32-bit unsigned words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -111,7 +111,7 @@ bool_t u32Parity(register u32 w) ******************************************************************************* */ -size_t SAFE(u32CTZ)(register u32 w) +size_t u32CTZ(register u32 w) { return 32 - u32Weight(w | (U32_0 - w)); } @@ -134,7 +134,7 @@ size_t FAST(u32CTZ)(register u32 w) return ((u32)(w << 1)) ? l - 2 : l - (w ? 1 : 0); } -size_t SAFE(u32CLZ)(register u32 w) +size_t u32CLZ(register u32 w) { w = w | w >> 1; w = w | w >> 2; @@ -234,6 +234,7 @@ void u32From(u32 dest[], const void* src, size_t count) { ASSERT(memIsValid(src, count)); ASSERT(memIsValid(dest, ((count + 3) / 4) * 4)); + ASSERT(memIsAligned(dest, 4)); memMove(dest, src, count); if (count % 4) memSetZero((octet*)dest + count, 4 - count % 4); @@ -247,17 +248,25 @@ void u32To(void* dest, size_t count, const u32 src[]) { ASSERT(memIsValid(src, (count + 3) / 4 * 4)); ASSERT(memIsValid(dest, count)); - memMove(dest, src, count); #if (OCTET_ORDER == BIG_ENDIAN) - if (count % 4) + if (count % 4) { size_t t = count / 4; register u32 u = src[t]; - for (t *= 4; t < count; ++t, u >>= 8) + memMove(dest, src, t *= 4); + for (; t < count; ++t, u >>= 8) ((octet*)dest)[t] = (octet)u; CLEAN(u); + count &= ~(size_t)3; } - for (count /= 4; count--;) - ((u32*)dest)[count] = u32Rev(((u32*)dest)[count]); + else + memMove(dest, src, count); + for (; count; count -= 4) + { + SWAP(((octet*)dest)[count - 4], ((octet*)dest)[count - 1]); + SWAP(((octet*)dest)[count - 3], ((octet*)dest)[count - 2]); + } +#else + memMove(dest, src, count); #endif // OCTET_ORDER } diff --git a/src/core/u64.c b/src/core/u64.c index 760ec545..c2560be2 100644 --- a/src/core/u64.c +++ b/src/core/u64.c @@ -4,7 +4,7 @@ \brief 64-bit unsigned words \project bee2 [cryptographic library] \created 2015.10.28 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -69,7 +69,7 @@ bool_t u64Parity(register u64 w) return (bool_t)(w & U64_1); } -size_t SAFE(u64CTZ)(register u64 w) +size_t u64CTZ(register u64 w) { return 64 - u64Weight(w | (U64_0 - w)); } @@ -92,7 +92,7 @@ size_t FAST(u64CTZ)(register u64 w) return ((u64)(w << 1)) ? l - 2 : l - (w ? 1 : 0); } -size_t SAFE(u64CLZ)(register u64 w) +size_t u64CLZ(register u64 w) { w = w | w >> 1; w = w | w >> 2; @@ -163,6 +163,7 @@ void u64From(u64 dest[], const void* src, size_t count) { ASSERT(memIsValid(src, count)); ASSERT(memIsValid(dest, ((count + 7) / 8) * 8)); + ASSERT(memIsAligned(dest, 8)); memMove(dest, src, count); if (count % 8) memSetZero((octet*)dest + count, 8 - count % 8); @@ -182,11 +183,20 @@ void u64To(void* dest, size_t count, const u64 src[]) { size_t t = count / 8; register u64 u = src[t]; - for (t *= 8; t < count; ++t, u >>= 8) + memMove(dest, src, t *= 8); + for (; t < count; ++t, u >>= 8) ((octet*)dest)[t] = (octet)u; CLEAN(u); + count &= ~(size_t)7; + } + else + memMove(dest, src, count); + for (; count; count -= 8) + { + SWAP(((octet*)dest)[count - 8], ((octet*)dest)[count - 1]); + SWAP(((octet*)dest)[count - 7], ((octet*)dest)[count - 2]); + SWAP(((octet*)dest)[count - 6], ((octet*)dest)[count - 3]); + SWAP(((octet*)dest)[count - 5], ((octet*)dest)[count - 4]); } - for (count /= 8; count--;) - ((u64*)dest)[count] = u64Rev(((u64*)dest)[count]); #endif // OCTET_ORDER } diff --git a/src/core/util.c b/src/core/util.c index 063eeb50..b54465d9 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -4,7 +4,7 @@ \brief Utilities \project bee2 [cryptographic library] \created 2012.05.10 -\version 2025.04.25 +\version 2025.09.05 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -121,35 +121,46 @@ void utilAssert(int b, const char* file, int line) size_t utilMin(size_t n, ...) { size_t min = SIZE_MAX; - va_list marker; + va_list args; ASSERT(n > 0); - va_start(marker, n); + va_start(args, n); while (n--) { - size_t current = va_arg(marker, size_t); + size_t current = va_arg(args, size_t); if (current < min) min = current; } - va_end(marker); + va_end(args); return min; } size_t utilMax(size_t n, ...) { size_t max = 0; - va_list marker; + va_list args; ASSERT(n > 0); - va_start(marker, n); + va_start(args, n); while (n--) { - size_t current = va_arg(marker, size_t); + size_t current = va_arg(args, size_t); if (current > max) max = current; } - va_end(marker); + va_end(args); return max; } +/* +******************************************************************************* +Выравнивание +******************************************************************************* +*/ + +size_t utilAlign(size_t size, size_t alignment) +{ + return (size + alignment - 1) / alignment * alignment; +} + /* ******************************************************************************* CRC32 diff --git a/src/crypto/bake.c b/src/crypto/bake.c deleted file mode 100644 index abda4f1b..00000000 --- a/src/crypto/bake.c +++ /dev/null @@ -1,1925 +0,0 @@ -/* -******************************************************************************* -\file bake.c -\brief STB 34.101.66 (bake): authenticated key establishment (AKE) protocols -\project bee2 [cryptographic library] -\created 2014.04.14 -\version 2025.04.25 -\copyright The Bee2 authors -\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). -******************************************************************************* -*/ - -#include "bee2/core/blob.h" -#include "bee2/core/err.h" -#include "bee2/core/mem.h" -#include "bee2/core/obj.h" -#include "bee2/core/util.h" -#include "bee2/crypto/bake.h" -#include "bee2/crypto/belt.h" -#include "bee2/math/qr.h" -#include "bee2/math/ecp.h" -#include "bee2/math/ww.h" -#include "bee2/math/zz.h" -#include "bign/bign_lcl.h" - -/* -******************************************************************************* -\todo Контроль последовательности выполнения шагов протоколов? -******************************************************************************* -*/ - -/* -******************************************************************************* -Алгоритм bakeKDF -******************************************************************************* -*/ - -err_t bakeKDF(octet key[32], const octet secret[], size_t secret_len, - const octet iv[], size_t iv_len, size_t num) -{ - void* state; - octet* block; - // проверить входные данные - if (!memIsValid(secret, secret_len) || - !memIsValid(iv, iv_len) || - !memIsValid(key, 32)) - return ERR_BAD_INPUT; - // создать состояние - state = blobCreate(utilMax(2, beltHash_keep(), beltKRP_keep() + 16)); - if (state == 0) - return ERR_OUTOFMEMORY; - block = (octet*)state + beltKRP_keep(); - // key <- beltHash(secret || iv) - beltHashStart(state); - beltHashStepH(secret, secret_len, state); - beltHashStepH(iv, iv_len, state); - beltHashStepG(key, state); - // key <- beltKRP(Y, 1^96, num) - memSet(block, 0xFF, 12); - beltKRPStart(state, key, 32, block); - CASSERT(B_PER_S <= 128); - memCopy(block, &num, sizeof(size_t)); -#if (OCTET_ORDER == BIG_ENDIAN) - memRev(block, sizeof(size_t)); -#endif - memSetZero(block + sizeof(size_t), 16 - sizeof(size_t)); - beltKRPStepG(key, 32, block, state); - // завершить - blobClose(state); - return ERR_OK; -} - -/* -******************************************************************************* -Алгоритм bakeSWU -******************************************************************************* -*/ - -static void bakeSWU2(word W[], const ec_o* ec, const octet X[], void* stack) -{ - octet* H; /* [no + 16] */ - word* s; /* [n + W_OF_O(16)] (совпадает с H) */ - // pre - ASSERT(ecIsOperable(ec)); - ASSERT(memIsValid(X, ec->f->no)); - ASSERT(wwIsValid(W, 2 * ec->f->n)); - // раскладка stack - H = (octet*)stack; - s = (word*)stack; - stack = H + ec->f->no + 16; - // H <- beltWBL(X, 0, 0) - memSetZero(H + ec->f->no, 16); - beltWBLStart(stack, H + ec->f->no, 16); - memCopy(H, X, ec->f->no); - beltWBLStepE(H, ec->f->no + 16, stack); - // s <- \bar H mod p - wwFrom(s, H, ec->f->no + 16); - zzMod(s, s, ec->f->n + W_OF_O(16), ec->f->mod, ec->f->n, stack); - // W <- ecpSWU(s) - wwTo(H, ec->f->no, s); - qrFrom(s, H, ec->f, stack); - ecpSWU(W, s, ec, stack); -} - -static size_t bakeSWU2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n) + 16 + - utilMax(3, - zzMod_deep(n + W_OF_O(16), n), - f_deep, - ecpSWU_deep(n, f_deep)); -} - -err_t bakeSWU(octet pt[], const bign_params* params, const octet msg[]) -{ - err_t code; - void* state; - word* W; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (!memIsValid(msg, params->l / 4) || - !memIsValid(pt, params->l / 2)) - return ERR_BAD_INPUT; - // создать состояние - state = blobCreate(bignStart_keep(params->l, bakeSWU2_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - // основные действия - W = (word*)pt; - bakeSWU2(W, (const ec_o*)state, msg, objEnd(state, void)); - wwTo(pt, params->l / 2, W); - // завершение - blobClose(state); - return ERR_OK; -} - -/* -******************************************************************************* -Шаги протокола BMQV - -\todo Оптимизировать вычисление s(V - (2^l + t)Q): - -- вычислить проективную кратную точку (2^l + t)Q и вычесть из нее - аффинную (пока нет функции вычисления проективной кратной точки); - -- находить сумму кратных точек sV + (- s(2^l + t))Q (ecAddMulAA). -[В последнем случае теряется малость t]. -******************************************************************************* -*/ - -typedef struct -{ - obj_hdr_t hdr; /*< заголовок */ -// ptr_table { - ec_o* ec; /*< описание эллиптической кривой */ - word* d; /*< [ec->f->n] долговременный личный ключ */ - word* u; /*< [ec->f->n] одноразовый личный ключ */ - octet* Vb; /*< [ec->f->no] ecX(Vb) */ -// } - bign_params params[1]; /*< параметры */ - bake_settings settings[1]; /*< настройки */ - bake_cert cert[1]; /*< сертификат */ - octet K0[32]; /*< ключ K0 */ - octet K1[32]; /*< ключ K1 */ - octet data[]; /*< данные */ -} bake_bmqv_o; - -static size_t bakeBMQV_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep); - -size_t bakeBMQV_keep(size_t l) -{ - const size_t n = W_OF_B(2 * l); - const size_t no = O_OF_B(2 * l); - return sizeof(bake_bmqv_o) + - bignStart_keep(l, bakeBMQV_deep) + - O_OF_W(2 * n) + no; -} - -err_t bakeBMQVStart(void* state, const bign_params* params, - const bake_settings* settings, const octet privkey[], - const bake_cert* cert) -{ - err_t code; - bake_bmqv_o* s = (bake_bmqv_o*)state; - size_t n, no; - // стек - word* Q; - void* stack; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(settings, sizeof(bake_settings)) || - !memIsNullOrValid(settings->helloa, settings->helloa_len) || - !memIsNullOrValid(settings->hellob, settings->hellob_len)) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (settings->rng == 0) - return ERR_BAD_RNG; - if (!memIsValid(privkey, params->l / 4) || - !memIsValid(cert, sizeof(bake_cert)) || - !memIsValid(cert->data, cert->len) || - cert->val == 0) - return ERR_BAD_INPUT; - // загрузить параметры - code = bignStart(s->data, params); - ERR_CALL_CHECK(code); - s->ec = (ec_o*)s->data; - n = s->ec->f->n, no = s->ec->f->no; - // сохранить параметры - memCopy(s->params, params, sizeof(bign_params)); - // сохранить настройки - memCopy(s->settings, settings, sizeof(bake_settings)); - // настроить указатели - s->d = objEnd(s->ec, word); - s->u = s->d + n; - s->Vb = (octet*)(s->u + n); - // настроить заголовок - s->hdr.keep = sizeof(bake_bmqv_o) + objKeep(s->ec) + O_OF_W(2 * n) + no; - s->hdr.p_count = 4; - s->hdr.o_count = 1; - // загрузить личный ключ - wwFrom(s->d, privkey, no); - // раскладка стека - Q = objEnd(s, word); - stack = Q + 2 * n; - // проверить сертификат и его открытый ключ - code = cert->val((octet*)Q, params, cert->data, cert->len); - ERR_CALL_CHECK(code); - if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) || - !qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) || - !ecpIsOnA(Q, s->ec, stack)) - return ERR_BAD_CERT; - // сохранить сертификат - memCopy(s->cert, cert, sizeof(bake_cert)); - // все нормально - return code; -} - -static size_t bakeBMQVStart_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(2 * n) + - utilMax(2, - f_deep, - ecpIsOnA_deep(n, f_deep)); -} - -err_t bakeBMQVStep2(octet out[], void* state) -{ - bake_bmqv_o* s = (bake_bmqv_o*)state; - size_t n, no; - // стек - word* Vb; /* [2 * n] */ - void* stack; - // обработать входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(out, 2 * no)) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 2 * no, s, objKeep(s))); - // раскладка стека - Vb = objEnd(s, word); - stack = Vb + 2 * n; - // ub <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // Vb <- ub G - if (!ecMulA(Vb, s->ec->base, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - // out <- - qrTo(out, ecX(Vb), s->ec->f, stack); - qrTo(out + no, ecY(Vb, n), s->ec->f, stack); - // сохранить ecX(Vb) - memCopy(s->Vb, out, no); - // все нормально - return ERR_OK; -} - -static size_t bakeBMQVStep2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(2 * n) + - utilMax(2, - f_deep, - ecMulA_deep(n, ec_d, ec_deep, n)); -} - -err_t bakeBMQVStep3(octet out[], const octet in[], const bake_cert* certb, - void* state) -{ - err_t code; - bake_bmqv_o* s = (bake_bmqv_o*)state; - size_t n, no; - // стек - word* Qb; /* [2 * n] */ - word* Va; /* [2 * n] */ - word* Vb; /* [2 * n] */ - word* t; /* [n / 2 + 1] */ - word* sa; /* [n + n / 2 + 1] */ - octet* K; /* [no] (совпадает с Qb) */ - octet* block0; /* [16] (совпадает с t) */ - octet* block1; /* [16] (следует за block0) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, 2 * no) || - !memIsValid(out, 2 * no + (s->settings->kca ? 8u : 0)) || - !memIsValid(certb, sizeof(bake_cert)) || - !memIsValid(certb->data, certb->len) || - certb->val == 0) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 2 * no + (s->settings->kca ? 8u : 0), - s, objKeep(s))); - // раскладка стека - Qb = objEnd(s, word); - Va = Qb + 2 * n; - Vb = Va + 2 * n; - t = Vb + 2 * n; - sa = t + n / 2 + 1; - stack = sa + n + n / 2 + 1; - K = (octet*)Qb; - block0 = (octet*)t; - block1 = block0 + 16; - ASSERT(block1 + 16 <= (octet*)stack); - // проверить certb - code = certb->val((octet*)Qb, s->params, certb->data, certb->len); - ERR_CALL_CHECK(code); - if (!qrFrom(ecX(Qb), (octet*)Qb, s->ec->f, stack) || - !qrFrom(ecY(Qb, n), (octet*)Qb + no, s->ec->f, stack) || - !ecpIsOnA(Qb, s->ec, stack)) - return ERR_BAD_CERT; - // Vb <- in, Vb \in E*? - if (!qrFrom(ecX(Vb), in, s->ec->f, stack) || - !qrFrom(ecY(Vb, n), in + no, s->ec->f, stack) || - !ecpIsOnA(Vb, s->ec, stack)) - return ERR_BAD_POINT; - // ua <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // Va <- ua G - if (!ecMulA(Va, s->ec->base, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo((octet*)Va, ecX(Va), s->ec->f, stack); - qrTo((octet*)Va + no, ecY(Va, n), s->ec->f, stack); - // t <- _2l || _2l)>_l - beltHashStart(stack); - beltHashStepH(Va, no, stack); - beltHashStepH(in, no, stack); - beltHashStepG2((octet*)t, no / 2, stack); - wwFrom(t, t, no / 2); - // out <- _4l - memCopy(out, Va, 2 * no); - // sa <- (ua - (2^l + t)da) \mod q - zzMul(sa, t, n / 2, s->d, n, stack); - sa[n + n / 2] = zzAdd2(sa + n / 2, s->d, n); - zzMod(sa, sa, n + n / 2 + 1, s->ec->order, n, stack); - zzSubMod(sa, s->u, sa, s->ec->order, n); - // K <- sa(Vb - (2^l + t)Qb), K == O => K <- G - t[n / 2] = 1; - if (!ecMulA(Qb, Qb, s->ec, t, n / 2 + 1, stack)) - return ERR_BAD_PARAMS; - if (!ecpSubAA(Vb, Vb, Qb, s->ec, stack)) - qrTo(K, s->ec->base, s->ec->f, stack); - else - { - if (!ecMulA(Vb, Vb, s->ec, sa, n, stack)) - return ERR_BAD_PARAMS; - qrTo(K, ecX(Vb), s->ec->f, stack); - } - // K <- beltHash(_2l || certa || certb || helloa || hellob) - beltHashStart(stack); - beltHashStepH(K, no, stack); - beltHashStepH(s->cert->data, s->cert->len, stack); - beltHashStepH(certb->data, certb->len, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - beltHashStepG(K, stack); - // K0 <- beltKRP(K, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, K, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(K, 1^96, 1) - if (s->settings->kca || s->settings->kcb) - { - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - } - // Ta <- beltMAC(0^128, K1), ...|| out <- Ta - if (s->settings->kca) - { - block0[0] = 0; - beltMACStart(stack, s->K1, 32); - beltMACStepA(block0, 16, stack); - beltMACStepG(out + 2 * no, stack); - } - // все нормально - return ERR_OK; -} - -static size_t bakeBMQVStep3_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(8 * n + 2) + - utilMax(9, - f_deep, - ecpIsOnA_deep(n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n), - ecpSubAA_deep(n, f_deep), - beltKRP_keep(), - beltMAC_keep()); -} - -err_t bakeBMQVStep4(octet out[], const octet in[], const bake_cert* certa, - void* state) -{ - err_t code; - bake_bmqv_o* s = (bake_bmqv_o*)state; - size_t n, no; - // стек - word* Qa; /* [2 * n] */ - word* Va; /* [2 * n] */ - word* t; /* [n / 2 + 1] */ - word* sb; /* [n + n / 2 + 1] */ - octet* K; /* [no] (совпадает с Qa) */ - octet* block0; /* [16] (совпадает с t) */ - octet* block1; /* [16] (следует за block0) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, 2 * no + (s->settings->kca ? 8u : 0)) || - !memIsValid(out, s->settings->kcb ? 8u : 0) || - !memIsValid(certa, sizeof(bake_cert)) || - !memIsValid(certa->data, certa->len) || - certa->val == 0) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, s->settings->kcb ? 8u : 0, s, objKeep(s))); - // раскладка стека - Qa = objEnd(s, word); - Va = Qa + 2 * n; - t = Va + 2 * n; - sb = t + n / 2 + 1; - stack = sb + n + n / 2 + 1; - K = (octet*)Qa; - block0 = (octet*)t; - block1 = block0 + 16; - ASSERT(block1 + 16 <= (octet*)stack); - // проверить certa - code = certa->val((octet*)Qa, s->params, certa->data, certa->len); - ERR_CALL_CHECK(code); - if (!qrFrom(ecX(Qa), (octet*)Qa, s->ec->f, stack) || - !qrFrom(ecY(Qa, n), (octet*)Qa + no, s->ec->f, stack) || - !ecpIsOnA(Qa, s->ec, stack)) - return ERR_BAD_CERT; - // Va <- in, Va \in E*? - if (!qrFrom(ecX(Va), in, s->ec->f, stack) || - !qrFrom(ecY(Va, n), in + no, s->ec->f, stack) || - !ecpIsOnA(Va, s->ec, stack)) - return ERR_BAD_POINT; - // t <- _2l || _2l)>_l - beltHashStart(stack); - beltHashStepH(in, no, stack); - beltHashStepH(s->Vb, no, stack); - beltHashStepG2((octet*)t, no / 2, stack); - wwFrom(t, t, no / 2); - // sb <- (ub - (2^l + t)db) \mod q - zzMul(sb, t, n / 2, s->d, n, stack); - sb[n + n / 2] = zzAdd2(sb + n / 2, s->d, n); - zzMod(sb, sb, n + n / 2 + 1, s->ec->order, n, stack); - zzSubMod(sb, s->u, sb, s->ec->order, n); - // K <- sb(Va - (2^l + t)Qa), K == O => K <- G - t[n / 2] = 1; - if (!ecMulA(Qa, Qa, s->ec, t, n / 2 + 1, stack)) - return ERR_BAD_PARAMS; - if (!ecpSubAA(Va, Va, Qa, s->ec, stack)) - qrTo(K, s->ec->base, s->ec->f, stack); - else - { - if (!ecMulA(Va, Va, s->ec, sb, n, stack)) - return ERR_BAD_PARAMS; - qrTo(K, ecX(Va), s->ec->f, stack); - } - // K <- beltHash(_2l || certa || certb || helloa || hellob) - beltHashStart(stack); - beltHashStepH(K, no, stack); - beltHashStepH(certa->data, certa->len, stack); - beltHashStepH(s->cert->data, s->cert->len, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - beltHashStepG(K, stack); - // K0 <- beltKRP(K, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, K, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(K, 1^96, 1) - if (s->settings->kca || s->settings->kcb) - { - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - } - // Ta == beltMAC(0^128, K1)? - if (s->settings->kca) - { - block0[0] = 0; - beltMACStart(stack, s->K1, 32); - beltMACStepA(block0, 16, stack); - if (!beltMACStepV(in + 2 * no, stack)) - return ERR_AUTH; - } - // Tb <- beltMAC(1^128, K1)? - if (s->settings->kcb) - { - beltMACStart(stack, s->K1, 32); - beltMACStepA(block1, 16, stack); - beltMACStepG(out, stack); - } - // все нормально - return ERR_OK; -} - -static size_t bakeBMQVStep4_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(6 * n + 2) + - utilMax(9, - f_deep, - ecpIsOnA_deep(n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n), - ecpSubAA_deep(n, f_deep), - beltKRP_keep(), - beltMAC_keep()); -} - -err_t bakeBMQVStep5(const octet in[8], void* state) -{ - bake_bmqv_o* s = (bake_bmqv_o*)state; - // стек - octet* block1; /* [16] */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - if (!s->settings->kcb) - return ERR_BAD_LOGIC; - if (!memIsValid(in, 8)) - return ERR_BAD_INPUT; - // раскладка стека - block1 = objEnd(s, octet); - stack = block1 + 16; - // Tb == beltMAC(1^128, K1)? - memSet(block1, 0xFF, 16); - beltMACStart(stack, s->K1, 32); - beltMACStepA(block1, 16, stack); - if (!beltMACStepV(in, stack)) - return ERR_AUTH; - // все нормально - return ERR_OK; -} - -static size_t bakeBMQVStep5_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return 16 + beltMAC_keep(); -} - -err_t bakeBMQVStepG(octet key[32], void* state) -{ - bake_bmqv_o* s = (bake_bmqv_o*)state; - // проверить входные данные - if (!objIsOperable(s) || - !memIsValid(key, 32)) - return ERR_BAD_INPUT; - // key <- K0 - memCopy(key, s->K0, 32); - // все нормально - return ERR_OK; -} - -static size_t bakeBMQV_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(5, - bakeBMQVStart_deep(n, f_deep, ec_d, ec_deep), - bakeBMQVStep2_deep(n, f_deep, ec_d, ec_deep), - bakeBMQVStep3_deep(n, f_deep, ec_d, ec_deep), - bakeBMQVStep4_deep(n, f_deep, ec_d, ec_deep), - bakeBMQVStep5_deep(n, f_deep, ec_d, ec_deep)); -} - -/* -******************************************************************************* -Выполнение BMQV -******************************************************************************* -*/ - -err_t bakeBMQVRunB(octet key[32], const bign_params* params, - const bake_settings* settings, const octet privkeyb[], - const bake_cert* certb, const bake_cert* certa, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [l / 2 + 8] */ - octet* out; /* [l / 2] */ - void* state; /* [bakeBMQV_keep()] */ - // проверить key - if (!memIsValid(key, 32)) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(params->l + 8 + bakeBMQV_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + params->l / 2 + 8; - state = out + params->l / 2; - // старт - code = bakeBMQVStart(state, params, settings, privkeyb, certb); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 2 - code = bakeBMQVStep2(out, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 2, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 4 - code = read(&len, in, params->l / 2 + (settings->kca ? 8u : 0), file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBMQVStep4(out, in, certa, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - if (settings->kcb) - { - code = write(&len, out, 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBMQVStepG(key, state); - blobClose(blob); - return code; -} - -err_t bakeBMQVRunA(octet key[32], const bign_params* params, - const bake_settings* settings, const octet privkeya[], - const bake_cert* certa, const bake_cert* certb, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [l / 2] */ - octet* out; /* [l / 2 + 8] */ - void* state; /* [bakeBMQV_keep()] */ - // проверить key - if (!memIsValid(key, 32)) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(params->l + 8 + bakeBMQV_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + params->l / 2; - state = out + params->l / 2 + 8; - // старт - code = bakeBMQVStart(state, params, settings, privkeya, certa); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 3 - code = read(&len, in, params->l / 2, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBMQVStep3(out, in, certb, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 2 + (settings->kca ? 8u : 0), file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 5 - if (settings->kcb) - { - code = read(&len, in, 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBMQVStep5(in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBMQVStepG(key, state); - blobClose(blob); - return code; -} - -/* -******************************************************************************* -Шаги протокола BSTS -******************************************************************************* -*/ - -typedef struct -{ - obj_hdr_t hdr; /*< заголовок */ -// ptr_table { - ec_o* ec; /*< описание эллиптической кривой */ - word* d; /*< [ec->f->n] долговременный личный ключ */ - word* u; /*< [ec->f->n] одноразовый личный ключ */ - word* t; /*< [ec->f->n / 2 + 1] t (совпадает с u) */ - word* Vb; /*< [2 * ec->f->n] Vb */ -// } - bign_params params[1]; /*< параметры */ - bake_settings settings[1]; /*< настройки */ - bake_cert cert[1]; /*< сертификат */ - octet K0[32]; /*< ключ K0 */ - octet K1[32]; /*< ключ K1 */ - octet K2[32]; /*< ключ K2 */ - octet data[]; /*< данные */ -} bake_bsts_o; - -static size_t bakeBSTS_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep); - -size_t bakeBSTS_keep(size_t l) -{ - const size_t n = W_OF_B(2 * l); - return sizeof(bake_bsts_o) + - bignStart_keep(l, bakeBSTS_deep) + - O_OF_W(4 * n); -} - -err_t bakeBSTSStart(void* state, const bign_params* params, - const bake_settings* settings, const octet privkey[], - const bake_cert* cert) -{ - err_t code; - bake_bsts_o* s = (bake_bsts_o*)state; - size_t n, no; - word* Q; - // стек - void* stack; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(settings, sizeof(bake_settings)) || - settings->kca != TRUE || settings->kcb != TRUE || - !memIsNullOrValid(settings->helloa, settings->helloa_len) || - !memIsNullOrValid(settings->hellob, settings->hellob_len)) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (settings->rng == 0) - return ERR_BAD_RNG; - if (!memIsValid(privkey, params->l / 4) || - !memIsValid(cert, sizeof(bake_cert)) || - !memIsValid(cert->data, cert->len) || - cert->val == 0) - return ERR_BAD_INPUT; - // загрузить параметры - code = bignStart(s->data, params); - ERR_CALL_CHECK(code); - s->ec = (ec_o*)s->data; - n = s->ec->f->n, no = s->ec->f->no; - // сохранить параметры - memCopy(s->params, params, sizeof(bign_params)); - // сохранить настройки - memCopy(s->settings, settings, sizeof(bake_settings)); - // настроить указатели - s->d = objEnd(s->ec, word); - s->u = s->d + n; - s->t = s->u; - s->Vb = s->u + n; - // настроить заголовок - s->hdr.keep = sizeof(bake_bsts_o) + objKeep(s->ec) + O_OF_W(4 * n); - s->hdr.p_count = 5; - s->hdr.o_count = 1; - // загрузить личный ключ - wwFrom(s->d, privkey, no); - // раскладка стека - stack = objEnd(s, void); - // проверить сертификат и его открытый ключ - Q = s->Vb; - code = cert->val((octet*)Q, params, cert->data, cert->len); - ERR_CALL_CHECK(code); - if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) || - !qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) || - !ecpIsOnA(Q, s->ec, stack)) - return ERR_BAD_CERT; - // сохранить сертификат - memCopy(s->cert, cert, sizeof(bake_cert)); - // все нормально - return code; -} - -static size_t bakeBSTSStart_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(2, - f_deep, - ecpIsOnA_deep(n, f_deep)); -} - -err_t bakeBSTSStep2(octet out[], void* state) -{ - bake_bsts_o* s = (bake_bsts_o*)state; - size_t n, no; - // стек - void* stack; - // обработать входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(out, 2 * no)) - return ERR_BAD_INPUT; - // раскладка стека - stack = objEnd(s, void); - // ub <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // Vb <- ub G - if (!ecMulA(s->Vb, s->ec->base, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - // out <- - qrTo(out, ecX(s->Vb), s->ec->f, stack); - qrTo(out + no, ecY(s->Vb, n), s->ec->f, stack); - // все нормально - return ERR_OK; -} - -static size_t bakeBSTSStep2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(2, - f_deep, - ecMulA_deep(n, ec_d, ec_deep, n)); -} - -err_t bakeBSTSStep3(octet out[], const octet in[], void* state) -{ - bake_bsts_o* s = (bake_bsts_o*)state; - size_t n, no; - // стек - word* Va; /* [2 * n] */ - word* t; /* [n / 2 + 1] */ - word* sa; /* [n + n / 2 + 1] */ - octet* K; /* [no] (совпадает с Va) */ - octet* block0; /* [16] (следует за sa) */ - octet* block1; /* [16] (следует за block0) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, 2 * no) || - !memIsValid(out, 3 * no + s->cert->len + 8)) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 3 * no + s->cert->len + 8, s, objKeep(s))); - // раскладка стека - Va = objEnd(s, word); - t = Va + 2 * n; - sa = t + n / 2 + 1; - K = (octet*)Va; - block0 = (octet*)(sa + n + n / 2 + 1); - block1 = block0 + 16; - stack = block1 + 16; - // Vb <- in, Vb \in E*? - if (!qrFrom(ecX(s->Vb), in, s->ec->f, stack) || - !qrFrom(ecY(s->Vb, n), in + no, s->ec->f, stack) || - !ecpIsOnA(s->Vb, s->ec, stack)) - return ERR_BAD_POINT; - // ua <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // Va <- ua G - if (!ecMulA(Va, s->ec->base, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo((octet*)Va, ecX(Va), s->ec->f, stack); - qrTo((octet*)Va + no, ecY(Va, n), s->ec->f, stack); - // t <- _2l || _2l)>_l - beltHashStart(stack); - beltHashStepH(Va, no, stack); - beltHashStepH(in, no, stack); - beltHashStepG2((octet*)t, no / 2, stack); - wwFrom(t, t, no / 2); - // out ||.. <- _4l - memCopy(out, Va, 2 * no); - // sa <- (ua - (2^l + t)da) \mod q - zzMul(sa, t, n / 2, s->d, n, stack); - sa[n + n / 2] = zzAdd2(sa + n / 2, s->d, n); - zzMod(sa, sa, n + n / 2 + 1, s->ec->order, n, stack); - zzSubMod(sa, s->u, sa, s->ec->order, n); - // ..|| out ||.. <- sa || certa - wwTo(out + 2 * no, no, sa); - memCopy(out + 3 * no, s->cert->data, s->cert->len); - // K <- beltHash(_2l || helloa || hellob) - if (!ecMulA(Va, s->Vb, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo(K, ecX(Va), s->ec->f, stack); - beltHashStart(stack); - beltHashStepH(K, no, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - beltHashStepG(K, stack); - // K0 <- beltKRP(K, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, K, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(K, 1^96, 1) - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - // K2 <- beltKRP(K, 1^96, 2) - block0[0] = 2; - beltKRPStepG(s->K2, 32, block0, stack); - // ..|| out ||.. <- beltCFBEncr(sa || certa) - block0[0] = 0; - beltCFBStart(stack, s->K2, 32, block0); - beltCFBStepE(out + 2 * no, no + s->cert->len, stack); - // ..|| out <- beltMAC(beltCFBEncr(sa || certa) || 0^128) - beltMACStart(stack, s->K1, 32); - beltMACStepA(out + 2 * no, no + s->cert->len, stack); - beltMACStepA(block0, 16, stack); - beltMACStepG(out + 3 * no + s->cert->len, stack); - // сохранить t - wwCopy(s->t, t, n / 2); - s->t[n / 2] = 1; - // все нормально - return ERR_OK; -} - -static size_t bakeBSTSStep3_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n + 2) + 32 + - utilMax(9, - f_deep, - ecpIsOnA_deep(n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n), - beltKRP_keep(), - beltCFB_keep(), - beltMAC_keep()); -} - -err_t bakeBSTSStep4(octet out[], const octet in[], size_t in_len, - bake_certval_i vala, void* state) -{ - err_t code; - bake_bsts_o* s = (bake_bsts_o*)state; - size_t n, no; - // стек - word* Va; /* [2 * n] */ - word* Qa; /* [2 * n] */ - word* t; /* [n / 2 + 1] */ - word* sa; /* [n] */ - word* sb; /* [n + n / 2 + 1] (совпадает с sa) */ - octet* K; /* [no] (совпадает с Qa) */ - octet* block0; /* [16] (следует за sb) */ - octet* block1; /* [16] (следует за block0) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (in_len <= 3 * no + 8 || - !memIsValid(in, in_len) || - vala == 0 || - !memIsValid(out, no + s->cert->len + 8)) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, no + s->cert->len + 8, s, objKeep(s))); - // раскладка стека - Va = objEnd(s, word); - Qa = Va + 2 * n; - t = Qa + 2 * n; - sa = sb = t + n / 2 + 1; - K = (octet*)Qa; - block0 = (octet*)(sb + n + n / 2 + 1); - block1 = block0 + 16; - stack = block1 + 16; - // Va <- in, Va \in E*? - if (!qrFrom(ecX(Va), in, s->ec->f, stack) || - !qrFrom(ecY(Va, n), in + no, s->ec->f, stack) || - !ecpIsOnA(Va, s->ec, stack)) - return ERR_BAD_POINT; - // K <- beltHash(_2l || helloa || hellob) - if (!ecMulA(Qa, Va, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo(K, ecX(Qa), s->ec->f, stack); - beltHashStart(stack); - beltHashStepH(K, no, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - beltHashStepG(K, stack); - // K0 <- beltKRP(K, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, K, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(K, 1^96, 1) - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - // K2 <- beltKRP(K, 1^96, 2) - block0[0] = 2; - beltKRPStepG(s->K2, 32, block0, stack); - // Ta == beltMAC(Ya || 0^128, K1)? - block0[0] = 0; - beltMACStart(stack, s->K1, 32); - beltMACStepA(in + 2 * no, in_len - 2 * no - 8, stack); - beltMACStepA(block0, 16, stack); - if (!beltMACStepV(in + in_len - 8, stack)) - return ERR_AUTH; - // обработать Ya = [in_len - 2 * no - 8]in - in_len -= 2 * no + 8; - { - blob_t Ya; - // sa || certa <- beltCFBDecr(Ya, K2, 0^128) - if ((Ya = blobCreate(in_len)) == 0) - return ERR_OUTOFMEMORY; - memCopy(Ya, in + 2 * no, in_len); - beltCFBStart(stack, s->K2, 32, block0); - beltCFBStepD(Ya, in_len, stack); - // sa \in {0, 1,..., q - 1}? - wwFrom(sa, Ya, no); - if (wwCmp(sa, s->ec->order, n) >= 0) - { - blobClose(Ya); - return ERR_AUTH; - } - // проверить certa - code = vala((octet*)Qa, s->params, (octet*)Ya + no, in_len - no); - ERR_CALL_HANDLE(code, blobClose(Ya)); - if (!qrFrom(ecX(Qa), (octet*)Qa, s->ec->f, stack) || - !qrFrom(ecY(Qa, n), (octet*)Qa + no, s->ec->f, stack) || - !ecpIsOnA(Qa, s->ec, stack)) - code = ERR_BAD_CERT; - blobClose(Ya); - ERR_CALL_CHECK(code); - } - // t <- _2l || _2l)>_l - beltHashStart(stack); - beltHashStepH(in, no, stack); - qrTo((octet*)s->Vb, s->Vb, s->ec->f, stack); - beltHashStepH(s->Vb, no, stack); - beltHashStepG2((octet*)t, no / 2, stack); - wwFrom(t, t, no / 2); - // sa G + (2^l + t)Qa == Va? - t[n / 2] = 1; - if (!ecAddMulA(Qa, s->ec, stack, 2, s->ec->base, sa, n, Qa, t, n / 2 + 1)) - return ERR_BAD_PARAMS; - if (!wwEq(Qa, Va, 2 * n)) - return ERR_AUTH; - // sb <- (ub - (2^l + t)db) \mod q - zzMul(sb, t, n / 2, s->d, n, stack); - sb[n + n / 2] = zzAdd2(sb + n / 2, s->d, n); - zzMod(sb, sb, n + n / 2 + 1, s->ec->order, n, stack); - zzSubMod(sb, s->u, sb, s->ec->order, n); - // out ||.. <- beltCFBEncr(sb || certb) - wwTo(out, no, sb); - memCopy(out + no, s->cert->data, s->cert->len); - beltCFBStart(stack, s->K2, 32, block1); - beltCFBStepE(out, no + s->cert->len, stack); - // .. || out <- beltMAC(beltCFBEncr(sb || certb) || 1^128) - beltMACStart(stack, s->K1, 32); - beltMACStepA(out, no + s->cert->len, stack); - beltMACStepA(block1, 16, stack); - beltMACStepG(out + no + s->cert->len, stack); - // все нормально - return ERR_OK; -} - -static size_t bakeBSTSStep4_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(6 * n + 2) + 32 + - utilMax(10, - f_deep, - ecpIsOnA_deep(n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1), - beltKRP_keep(), - beltCFB_keep(), - beltMAC_keep()); -} - -err_t bakeBSTSStep5(const octet in[], size_t in_len, bake_certval_i valb, - void* state) -{ - err_t code; - bake_bsts_o* s = (bake_bsts_o*)state; - size_t n, no; - // стек - word* Qb; /* [2 * n] */ - word* sb; /* [n] */ - octet* block1; /* [16] (совпадает с Qb) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (in_len <= no + 8 || - !memIsValid(in, in_len) || - valb == 0) - return ERR_BAD_INPUT; - // раскладка стека - Qb = objEnd(s, word); - sb = Qb + 2 * n; - stack = sb + n; - block1 = (octet*)Qb; - // Tb == beltMAC(Yb || 1^128, K1)? - memSet(block1, 0xFF, 16); - beltMACStart(stack, s->K1, 32); - beltMACStepA(in, in_len - 8, stack); - beltMACStepA(block1, 16, stack); - if (!beltMACStepV(in + in_len - 8, stack)) - return ERR_AUTH; - // обработать Yb = [in_len - 8]in - in_len -= 8; - { - blob_t Yb; - // sb || certb <- beltCFBDecr(Yb, K2, 1^128) - if ((Yb = blobCreate(in_len)) == 0) - return ERR_OUTOFMEMORY; - memCopy(Yb, in, in_len); - beltCFBStart(stack, s->K2, 32, block1); - beltCFBStepD(Yb, in_len, stack); - // sb \in {0, 1,..., q - 1}? - wwFrom(sb, Yb, no); - if (wwCmp(sb, s->ec->order, n) >= 0) - { - blobClose(Yb); - return ERR_AUTH; - } - // проверить certa - code = valb((octet*)Qb, s->params, (octet*)Yb + no, in_len - no); - ERR_CALL_HANDLE(code, blobClose(Yb)); - if (!qrFrom(ecX(Qb), (octet*)Qb, s->ec->f, stack) || - !qrFrom(ecY(Qb, n), (octet*)Qb + no, s->ec->f, stack) || - !ecpIsOnA(Qb, s->ec, stack)) - code = ERR_BAD_CERT; - blobClose(Yb); - ERR_CALL_CHECK(code); - } - // sb G + (2^l + t)Qa == Vb? - if (!ecAddMulA(Qb, s->ec, stack, 2, s->ec->base, sb, n, - Qb, s->t, n / 2 + 1)) - return ERR_BAD_PARAMS; - if (!wwEq(Qb, s->Vb, 2 * n)) - return ERR_AUTH; - // все нормально - return ERR_OK; -} - -static size_t bakeBSTSStep5_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + - utilMax(5, - beltMAC_keep(), - beltCFB_keep(), - f_deep, - ecpIsOnA_deep(n, f_deep), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)); -} - -err_t bakeBSTSStepG(octet key[32], void* state) -{ - bake_bsts_o* s = (bake_bsts_o*)state; - // проверить входные данные - if (!objIsOperable(s) || - !memIsValid(key, 32)) - return ERR_BAD_INPUT; - // key <- K0 - memCopy(key, s->K0, 32); - // все нормально - return ERR_OK; -} - -static size_t bakeBSTS_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(5, - bakeBSTSStart_deep(n, f_deep, ec_d, ec_deep), - bakeBSTSStep2_deep(n, f_deep, ec_d, ec_deep), - bakeBSTSStep3_deep(n, f_deep, ec_d, ec_deep), - bakeBSTSStep4_deep(n, f_deep, ec_d, ec_deep), - bakeBSTSStep5_deep(n, f_deep, ec_d, ec_deep)); -} - -/* -******************************************************************************* -Выполнение BSTS -******************************************************************************* -*/ - -err_t bakeBSTSRunB(octet key[32], const bign_params* params, - const bake_settings* settings, const octet privkeyb[], - const bake_cert* certb, bake_certval_i vala, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [512] */ - octet* out; /* [MAX2(l / 2, l / 4 + certb->len + 8)] */ - void* state; /* [bakeBSTS_keep()] */ - // проверить входные данные - if (!memIsValid(key, 32) || - !memIsValid(certb, sizeof(bake_cert))) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(512 + - MAX2(params->l / 2, params->l / 4 + certb->len + 8) + - bakeBSTS_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + 512; - state = out + MAX2(params->l / 2, params->l / 4 + certb->len + 8); - // старт - code = bakeBSTSStart(state, params, settings, privkeyb, certb); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 2 - code = bakeBSTSStep2(out, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 2, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 4: прочитать блок M2 - code = read(&len, in, 512, file); - // шаг 4: M2 из одного блока? - if (code == ERR_MAX) - { - code = bakeBSTSStep4(out, in, len, vala, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 4 + certb->len + 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // шаг 4: ошибка при чтении - else if (code != ERR_OK) - { - blobClose(blob); - return code; - } - // шаг 4: обработать M2 из нескольких блоков - else - { - blob_t M2 = 0; - while (code == ERR_OK) - { - if ((M2 = blobResize(M2, blobSize(M2) + len)) == 0) - { - blobClose(blob); - return ERR_OUTOFMEMORY; - } - memCopy((octet*)M2 + blobSize(M2) - len, in, len); - code = read(&len, in, 512, file); - } - if (code != ERR_MAX) - { - blobClose(M2); - blobClose(blob); - return code; - } - if ((M2 = blobResize(M2, blobSize(M2) + len)) == 0) - { - blobClose(blob); - return ERR_OUTOFMEMORY; - } - memCopy((octet*)M2 + blobSize(M2) - len, in, len); - code = bakeBSTSStep4(out, M2, blobSize(M2), vala, state); - blobClose(M2); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 4 + certb->len + 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBSTSStepG(key, state); - blobClose(blob); - return code; -} - -err_t bakeBSTSRunA(octet key[32], const bign_params* params, - const bake_settings* settings, const octet privkeya[], - const bake_cert* certa, bake_certval_i valb, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [MAX2(512, l / 2)] */ - octet* out; /* [3 * l / 4 + certa->len + 8] */ - void* state; /* [bakeBSTS_keep()] */ - // проверить входные данные - if (!memIsValid(key, 32) || - !memIsValid(certa, sizeof(bake_cert))) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(MAX2(512, params->l / 2) + 3 * params->l / 4 + - certa->len + 8 + bakeBSTS_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + MAX2(512, params->l / 2); - state = out + 3 * params->l / 4 + certa->len + 8; - // старт - code = bakeBSTSStart(state, params, settings, privkeya, certa); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 3 - code = read(&len, in, params->l / 2, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBSTSStep3(out, in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, 3 * params->l / 4 + certa->len + 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 5: прочитать блок M3 - code = read(&len, in, 512, file); - // шаг 5: M3 из одного блока? - if (code == ERR_MAX) - { - code = bakeBSTSStep5(in, len, valb, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // шаг 5: ошибка при чтении - else if (code != ERR_OK) - { - blobClose(blob); - return code; - } - // шаг 5: обработать M3 из нескольких блоков - else - { - blob_t M3 = 0; - while (code == ERR_OK) - { - if ((M3 = blobResize(M3, blobSize(M3) + len)) == 0) - { - blobClose(blob); - return ERR_OUTOFMEMORY; - } - memCopy((octet*)M3 + blobSize(M3) - len, in, len); - code = read(&len, in, 512, file); - } - if (code != ERR_MAX) - { - blobClose(M3); - blobClose(blob); - return code; - } - if ((M3 = blobResize(M3, blobSize(M3) + len)) == 0) - { - blobClose(blob); - return ERR_OUTOFMEMORY; - } - memCopy((octet*)M3 + blobSize(M3) - len, in, len); - code = bakeBSTSStep5(M3, blobSize(M3), valb, state); - blobClose(M3); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBSTSStepG(key, state); - blobClose(blob); - return code; -} - -/* -******************************************************************************* -Шаги протокола BPACE -******************************************************************************* -*/ - -typedef struct -{ - obj_hdr_t hdr; /*< заголовок */ -// ptr_table { - ec_o* ec; /*< описание эллиптической кривой */ - octet* R; /*< [ec->f->no](Ra || Rb или ecX(Va)) */ - word* W; /*< [2 * ec->f->n] точка W */ - word* u; /*< [ec->f->n] ua или ub */ -// } - bake_settings settings[1]; /*< настройки */ - octet K0[32]; /*< ключ K0 */ - octet K1[32]; /*< ключ K1 */ - octet K2[32]; /*< ключ K2 */ - octet data[]; /*< данные */ -} bake_bpace_o; - -static size_t bakeBPACE_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep); - -size_t bakeBPACE_keep(size_t l) -{ - const size_t n = W_OF_B(2 * l); - const size_t no = O_OF_B(2 * l); - return sizeof(bake_bpace_o) + - bignStart_keep(l, bakeBPACE_deep) + - no + O_OF_W(3 * n); -} - -err_t bakeBPACEStart(void* state, const bign_params* params, - const bake_settings* settings, const octet pwd[], size_t pwd_len) -{ - err_t code; - bake_bpace_o* s = (bake_bpace_o*)state; - size_t n, no; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(settings, sizeof(bake_settings)) || - !memIsNullOrValid(settings->helloa, settings->helloa_len) || - !memIsNullOrValid(settings->hellob, settings->hellob_len) || - !memIsValid(pwd, pwd_len)) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (settings->rng == 0) - return ERR_BAD_RNG; - // загрузить параметры - code = bignStart(s->data, params); - ERR_CALL_CHECK(code); - s->ec = (ec_o*)s->data; - n = s->ec->f->n, no = s->ec->f->no; - // загрузить настройки - memCopy(s->settings, settings, sizeof(bake_settings)); - // настроить указатели - s->R = objEnd(s->ec, octet); - s->W = (word*)(s->R + no); - s->u = s->W + 2 * n; - // настроить заголовок - s->hdr.keep = sizeof(bake_bpace_o) + objKeep(s->ec) + no + O_OF_W(3 * n); - s->hdr.p_count = 4; - s->hdr.o_count = 1; - // K2 <- beltHash(pwd) - beltHashStart(objEnd(s, void)); - beltHashStepH(pwd, pwd_len, objEnd(s, void)); - beltHashStepG(s->K2, objEnd(s, void)); - // все нормально - return code; -} - -static size_t bakeBPACEStart_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return beltHash_keep(); -} - -err_t bakeBPACEStep2(octet out[], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - size_t no; - // стек - void* stack; - // обработать входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - no = s->ec->f->no; - if (!memIsValid(out, no / 2)) - return ERR_BAD_INPUT; - // раскладка стека - stack = objEnd(s, void); - // Rb <-R {0, 1}^l - s->settings->rng(out, no / 2, s->settings->rng_state); - memCopy(s->R + no / 2, out, no / 2); - // out <- beltECB(Rb, K2) - beltECBStart(stack, s->K2, 32); - beltECBStepE(out, no / 2, stack); - // все нормально - return ERR_OK; -} - -static size_t bakeBPACEStep2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return beltECB_keep(); -} - -err_t bakeBPACEStep3(octet out[], const octet in[], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - size_t n, no; - // стек - word* Va; /* [2 * n] */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, no / 2) || - !memIsValid(out, 5 * no / 2)) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 5 * no / 2, s, objKeep(s))); - // раскладка стека - Va = objEnd(s, word); - stack = Va + 2 * n; - // Rb <- beltECBDecr(Yb, K2) - memCopy(s->R + no / 2, in, no / 2); - beltECBStart(stack, s->K2, 32); - beltECBStepD(s->R + no / 2, no / 2, stack); - // Ra <-R {0, 1}^l - s->settings->rng(out, no / 2, s->settings->rng_state); - memCopy(s->R, out, no / 2); - // out ||... <- beltECBEncr(Ra, K2) - beltECBStart(stack, s->K2, 32); - beltECBStepE(out, no / 2, stack); - // W <- bakeSWU(Ra || Rb) - bakeSWU2(s->W, s->ec, s->R, stack); - // ua <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // Va <- ua W - if (!ecMulA(Va, s->W, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - // ...|| out <- - qrTo(out + no / 2, ecX(Va), s->ec->f, stack); - qrTo(out + 3 * no / 2, ecY(Va, n), s->ec->f, stack); - // сохранить x-координату Va - memCopy(s->R, out + no / 2, no); - // все нормально - return ERR_OK; -} - -static size_t bakeBPACEStep3_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(2 * n) + - utilMax(4, - beltECB_keep(), - bakeSWU2_deep(n, f_deep, ec_d, ec_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - f_deep); -} - -err_t bakeBPACEStep4(octet out[], const octet in[], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - size_t n, no; - // стек - word* Va; /* [2 * n] */ - word* K; /* [2 * n] (совпадает c Va) */ - octet* Y; /* [32] (совпадает c K) */ - word* Vb; /* [2 * n] (смещен на n относительно Va) */ - octet* block0; /* [16] (совпадает с Vb) */ - octet* block1; /* [16] (следует за block1) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, 5 * no / 2) || - !memIsValid(out, 2 * no + (s->settings->kcb ? 8u : 0))) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 2 * no + (s->settings->kcb ? 8u : 0), - s, objKeep(s))); - // раскладка стека [Y должен умещаться в no октетов] - Va = K = objEnd(s, word); - Y = (octet*)K; - Vb = K + n; - block0 = (octet*)Vb; - block1 = block0 + 16; - stack = Vb + 2 * n; - ASSERT(32 <= no); - // Va <- ... || in, Va \in E*? - if (!qrFrom(ecX(Va), in + no / 2, s->ec->f, stack) || - !qrFrom(ecY(Va, n), in + no / 2 + no, s->ec->f, stack) || - !ecpIsOnA(Va, s->ec, stack)) - return ERR_BAD_POINT; - // Ra <- beltECBDecr(in ||..., K2) - memCopy(s->R, in, no / 2); - beltECBStart(stack, s->K2, 32); - beltECBStepD(s->R, no / 2, stack); - // W <- bakeSWU(Ra || Rb) - bakeSWU2(s->W, s->ec, s->R, stack); - // ub <-R {1, 2, ..., q - 1} - if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, - s->settings->rng_state)) - return ERR_BAD_RNG; - // K <- ub Va - if (!ecMulA(K, Va, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo((octet*)K, ecX(K), s->ec->f, stack); - // Vb <- ub W - if (!ecMulA(Vb, s->W, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo((octet*)ecX(Vb), ecX(Vb), s->ec->f, stack); - qrTo((octet*)ecY(Vb, n), ecY(Vb, n), s->ec->f, stack); - // Y <- beltHash(_2l || _2l || _2l || helloa || hellob) - beltHashStart(stack); - beltHashStepH(K, no, stack); - beltHashStepH(in + no / 2, no, stack); - beltHashStepH(Vb, no, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - beltHashStepG(Y, stack); - // out ||... <- - memCopy(out, ecX(Vb), no); - memCopy(out + no, ecY(Vb, n), no); - // K0 <- beltKRP(Y, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, Y, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(Y, 1^96, 1) - if (s->settings->kca || s->settings->kcb) - { - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - } - // Tb <- beltMAC(1^128, K1), ...|| out <- Tb - if (s->settings->kcb) - { - beltMACStart(stack, s->K1, 32); - beltMACStepA(block1, 16, stack); - beltMACStepG(out + 2 * no, stack); - } - // все нормально - return ERR_OK; -} - -static size_t bakeBPACEStep4_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + - utilMax(7, - f_deep, - beltECB_keep(), - bakeSWU2_deep(n, f_deep, ec_d, ec_deep), - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - beltKRP_keep(), - beltMAC_keep()); -} - -err_t bakeBPACEStep5(octet out[], const octet in[], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - size_t n, no; - // стек - word* Vb; /* [2 * n] */ - word* K; /* [2 * n] (смещен на n относительно Vb) */ - octet* Y; /* [32] (совпадает c Vb) */ - octet* block0; /* [16] (следует за Y) */ - octet* block1; /* [16] (следует за block0) */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - n = s->ec->f->n, no = s->ec->f->no; - if (!memIsValid(in, 2 * no + (s->settings->kcb ? 8u : 0)) || - !memIsValid(out, s->settings->kca ? 8u : 0)) - return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, s->settings->kca ? 8u : 0, s, objKeep(s))); - // раскладка стека [Y || block0 || block1 должны умещаться в 3 * n слов] - Vb = objEnd(s, word); - K = Vb + n; - Y = (octet*)Vb; - block0 = Y + 32; - block1 = block0 + 16; - stack = K + 2 * n; - ASSERT(32 + 16 + 16 <= 3 * no); - // Vb <- in ||..., Vb \in E*? - if (!qrFrom(ecX(Vb), in, s->ec->f, stack) || - !qrFrom(ecY(Vb, n), in + no, s->ec->f, stack) || - !ecpIsOnA(Vb, s->ec, stack)) - return ERR_BAD_POINT; - // K <- ua Vb - if (!ecMulA(K, Vb, s->ec, s->u, n, stack)) - return ERR_BAD_PARAMS; - qrTo((octet*)K, ecX(K), s->ec->f, stack); - qrTo((octet*)Vb, ecX(Vb), s->ec->f, stack); - // Y <- beltHash(_2l || _2l || _2l || helloa || hellob) - beltHashStart(stack); - beltHashStepH(K, no, stack); - beltHashStepH(s->R, no, stack); - beltHashStepH(Vb, no, stack); - if (s->settings->helloa) - beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); - if (s->settings->hellob) - beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); - ASSERT(no >= 32); - beltHashStepG(Y, stack); - // K0 <- beltKRP(Y, 1^96, 0) - memSetZero(block0, 16); - memSet(block1, 0xFF, 16); - beltKRPStart(stack, Y, 32, block1); - beltKRPStepG(s->K0, 32, block0, stack); - // K1 <- beltKRP(Y, 1^96, 1) - if (s->settings->kca || s->settings->kcb) - { - block0[0] = 1; - beltKRPStepG(s->K1, 32, block0, stack); - } - // Tb == beltMAC(1^128, K1)? - if (s->settings->kcb) - { - beltMACStart(stack, s->K1, 32); - beltMACStepA(block1, 16, stack); - if (!beltMACStepV(in + 2 * no, stack)) - return ERR_AUTH; - } - // Ta <- beltMAC(0^128, K1) - if (s->settings->kca) - { - block0[0] = 0; - beltMACStart(stack, s->K1, 32); - beltMACStepA(block0, 16, stack); - beltMACStepG(out, stack); - } - // все нормально - return ERR_OK; -} - -static size_t bakeBPACEStep5_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + - utilMax(5, - f_deep, - ecMulA_deep(n, ec_d, ec_deep, n), - beltHash_keep(), - beltKRP_keep(), - beltMAC_keep()); -} - -err_t bakeBPACEStep6(const octet in[8], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - // стек - octet* block0; /* [16] */ - void* stack; - // проверить входные данные - if (!objIsOperable(s)) - return ERR_BAD_INPUT; - if (!s->settings->kca) - return ERR_BAD_LOGIC; - if (!memIsValid(in, 8)) - return ERR_BAD_INPUT; - // раскладка стека - block0 = objEnd(s, octet); - stack = block0 + 16; - // Ta == beltMAC(0^128, K1)? - memSetZero(block0, 16); - beltMACStart(stack, s->K1, 32); - beltMACStepA(block0, 16, stack); - if (!beltMACStepV(in, stack)) - return ERR_AUTH; - // все нормально - return ERR_OK; -} - -static size_t bakeBPACEStep6_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return 16 + beltMAC_keep(); -} - -err_t bakeBPACEStepG(octet key[32], void* state) -{ - bake_bpace_o* s = (bake_bpace_o*)state; - // проверить входные данные - if (!objIsOperable(s) || - !memIsValid(key, 32)) - return ERR_BAD_INPUT; - // key <- K0 - memCopy(key, s->K0, 32); - // все нормально - return ERR_OK; -} - -static size_t bakeBPACE_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(6, - bakeBPACEStart_deep(n, f_deep, ec_d, ec_deep), - bakeBPACEStep2_deep(n, f_deep, ec_d, ec_deep), - bakeBPACEStep3_deep(n, f_deep, ec_d, ec_deep), - bakeBPACEStep4_deep(n, f_deep, ec_d, ec_deep), - bakeBPACEStep5_deep(n, f_deep, ec_d, ec_deep), - bakeBPACEStep6_deep(n, f_deep, ec_d, ec_deep)); -} - -/* -******************************************************************************* -Выполнение BPACE -******************************************************************************* -*/ - -err_t bakeBPACERunB(octet key[32], const bign_params* params, - const bake_settings* settings, const octet pwd[], size_t pwd_len, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [5 * l / 8] */ - octet* out; /* [l / 2 + 8] */ - void* state; /* [bakeBPACE_keep()] */ - // проверить key - if (!memIsValid(key, 32)) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(9 * params->l / 8 + 8 + bakeBPACE_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + 5 * params->l / 8; - state = out + params->l / 2 + 8; - // старт - code = bakeBPACEStart(state, params, settings, pwd, pwd_len); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 2 - code = bakeBPACEStep2(out, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 4 - code = read(&len, in, 5 * params->l / 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBPACEStep4(out, in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, params->l / 2 + (settings->kcb ? 8u : 0), file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 6 - if (settings->kca) - { - code = read(&len, in, 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBPACEStep6(in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBPACEStepG(key, state); - blobClose(blob); - return code; -} - -err_t bakeBPACERunA(octet key[32], const bign_params* params, - const bake_settings* settings, const octet pwd[], size_t pwd_len, - read_i read, write_i write, void* file) -{ - err_t code; - size_t len; - // блоб - blob_t blob; - octet* in; /* [l / 2 + 8] */ - octet* out; /* [5 * l / 8] */ - void* state; /* [bakeBPACE_keep()] */ - // проверить key - if (!memIsValid(key, 32)) - return ERR_BAD_INPUT; - // создать блоб - if (params->l != 128 && params->l != 192 && params->l != 256) - return ERR_BAD_PARAMS; - blob = blobCreate(9 * params->l / 8 + 8 + bakeBPACE_keep(params->l)); - if (blob == 0) - return ERR_OUTOFMEMORY; - // раскладка блоба - in = (octet*)blob; - out = in + params->l / 2 + 8; - state = out + 5 * params->l / 8; - // старт - code = bakeBPACEStart(state, params, settings, pwd, pwd_len); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 3 - code = read(&len, in, params->l / 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBPACEStep3(out, in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = write(&len, out, 5 * params->l / 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - // шаг 5 - code = read(&len, in, params->l / 2 + (settings->kcb ? 8u : 0), file); - ERR_CALL_HANDLE(code, blobClose(blob)); - code = bakeBPACEStep5(out, in, state); - ERR_CALL_HANDLE(code, blobClose(blob)); - if (settings->kca) - { - code = write(&len, out, 8, file); - ERR_CALL_HANDLE(code, blobClose(blob)); - } - // завершение - code = bakeBPACEStepG(key, state); - blobClose(blob); - return code; -} diff --git a/src/crypto/bake/bake_bmqv.c b/src/crypto/bake/bake_bmqv.c new file mode 100644 index 00000000..e9ce5be4 --- /dev/null +++ b/src/crypto/bake/bake_bmqv.c @@ -0,0 +1,619 @@ +/* +******************************************************************************* +\file bake_bmqv.c +\brief STB 34.101.66 (bake): the BMQV protocol +\project bee2 [cryptographic library] +\created 2014.04.14 +\version 2025.09.26 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#include "bee2/core/blob.h" +#include "bee2/core/err.h" +#include "bee2/core/mem.h" +#include "bee2/core/obj.h" +#include "bee2/core/util.h" +#include "bee2/crypto/bake.h" +#include "bee2/crypto/belt.h" +#include "bee2/crypto/bign.h" +#include "bee2/math/qr.h" +#include "bee2/math/ecp.h" +#include "bee2/math/ww.h" +#include "bee2/math/zz.h" +#include "../bign/bign_lcl.h" +#include "bake_lcl.h" + +/* +******************************************************************************* +Шаги протокола BMQV + +\todo Оптимизировать вычисление s(V - (2^l + t)Q): + -- вычислить проективную кратную точку (2^l + t)Q и вычесть из нее + аффинную (пока нет функции вычисления проективной кратной точки); + -- находить сумму кратных точек sV + (- s(2^l + t))Q (ecAddMulAA). +[В последнем случае теряется малость t]. + +\todo Контроль последовательности выполнения шагов? +******************************************************************************* +*/ + +typedef struct +{ + bign_params params[1]; /*< параметры */ + bake_settings settings[1]; /*< настройки */ + bake_cert cert[1]; /*< сертификат */ + octet K0[32]; /*< ключ K0 */ + octet K1[32]; /*< ключ K1 */ + ec_o* ec; /*< эллиптическая кривая */ + word* d; /*< [n] долговременный личный ключ */ + word* u; /*< [n] одноразовый личный ключ */ + octet* Vb; /*< [no] ecX(Vb) */ + void* stack; /*< [bakeBMQV_deep] стек */ + mem_align_t data[]; /*< данные */ +} bake_bmqv_st; + +static size_t bakeBMQV_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep); + +#define bakeBMQV_state(n, no)\ +/* d */ O_OF_W(n),\ +/* u */ O_OF_W(n),\ +/* Vb */ no + +size_t bakeBMQV_keep(size_t l) +{ + const size_t n = W_OF_B(2 * l); + const size_t no = O_OF_B(2 * l); + return sizeof(bake_bmqv_st) + + memSliceSize( + bakeEcStart_keep(l, bakeBMQV_deep), + bakeBMQV_state(n, no), + SIZE_MAX); +} + +#define bakeBMQVStart_local(n)\ +/* Q */ O_OF_W(2 * n) + +err_t bakeBMQVStart(void* state, const bign_params* params, + const bake_settings* settings, const octet privkey[], + const bake_cert* cert) +{ + err_t code; + bake_bmqv_st* s = (bake_bmqv_st*)state; + size_t n, no; + word* Q; /* [2 * n] */ + void* stack; + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(settings, sizeof(bake_settings)) || + !memIsNullOrValid(settings->helloa, settings->helloa_len) || + !memIsNullOrValid(settings->hellob, settings->hellob_len) || + !memIsValid(privkey, params->l / 4) || + !memIsValid(cert, sizeof(bake_cert)) || + !memIsValid(cert->data, cert->len) || + cert->val == 0) + return ERR_BAD_INPUT; + if (settings->rng == 0) + return ERR_BAD_RNG; + // развернуть кривую + code = bakeEcStart(s->data, params); + ERR_CALL_CHECK(code); + memSlice(s->data, + objKeep(s->data), SIZE_0, SIZE_MAX, + &s->ec, &stack); + n = s->ec->f->n, no = s->ec->f->no; + // разметить состояние и стек + memSlice(stack, + bakeBMQV_state(n, no), SIZE_0, + bakeBMQVStart_local(n), SIZE_0, SIZE_MAX, + &s->d, &s->u, &s->Vb, &s->stack, + &Q, &stack); + // сохранить параметры + memCopy(s->params, params, sizeof(bign_params)); + // сохранить настройки + memCopy(s->settings, settings, sizeof(bake_settings)); + // загрузить личный ключ + wwFrom(s->d, privkey, no); + // проверить сертификат и его открытый ключ + code = cert->val((octet*)Q, params, cert->data, cert->len); + ERR_CALL_CHECK(code); + if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) || + !qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) || + !ecpIsOnA(Q, s->ec, stack)) + return ERR_BAD_CERT; + // сохранить сертификат + memCopy(s->cert, cert, sizeof(bake_cert)); + // завершение + return code; +} + +static size_t bakeBMQVStart_deep(size_t n, size_t f_deep) +{ + return memSliceSize( + bakeBMQVStart_local(n), + utilMax(2, + f_deep, + ecpIsOnA_deep(n, f_deep)), + SIZE_MAX); +} + +#define bakeBMQVStep2_local(n)\ +/* Vb */ O_OF_W(2 * n) + +err_t bakeBMQVStep2(octet out[], void* state) +{ + bake_bmqv_st* s = (bake_bmqv_st*)state; + size_t n, no; + word* Vb; /* [2 * n] */ + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bmqv_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(out, 2 * no)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBMQVStep2_local(n), SIZE_0, SIZE_MAX, + &Vb, &stack); + // ub <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // Vb <- ub G + if (!ecMulA(Vb, s->ec->base, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + // out <- + qrTo(out, ecX(Vb), s->ec->f, stack); + qrTo(out + no, ecY(Vb, n), s->ec->f, stack); + // сохранить ecX(Vb) + memCopy(s->Vb, out, no); + // завершение + return ERR_OK; +} + +static size_t bakeBMQVStep2_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBMQVStep2_local(n), + utilMax(2, + f_deep, + ecMulA_deep(n, ec_d, ec_deep, n)), + SIZE_MAX); +} + +#define bakeBMQVStep3_local(n, no)\ +/* Qb */ O_OF_W(2 * n),\ +/* K */ no | SIZE_HI,\ +/* Va */ O_OF_W(2 * n),\ +/* Vb */ O_OF_W(2 * n),\ +/* t */ O_OF_W(n / 2 + 1),\ +/* block0 */ (size_t)16 | SIZE_HI,\ +/* sa */ O_OF_W(n + n / 2 + 1),\ +/* block1 */ (size_t)16 | SIZE_HI + +err_t bakeBMQVStep3(octet out[], const octet in[], const bake_cert* certb, + void* state) +{ + err_t code; + bake_bmqv_st* s = (bake_bmqv_st*)state; + size_t n, no; + word* Qb; /* [2 * n] */ + word* Va; /* [2 * n] */ + word* Vb; /* [2 * n] */ + word* t; /* [n / 2 + 1] */ + word* sa; /* [n + n / 2 + 1] */ + octet* K; /* [no] (|Qb) */ + octet* block0; /* [16] (|t) */ + octet* block1; /* [16] (|sa) */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bmqv_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, 2 * no) || + !memIsValid(out, 2 * no + (s->settings->kca ? 8u : 0)) || + !memIsValid(certb, sizeof(bake_cert)) || + !memIsValid(certb->data, certb->len) || + certb->val == 0) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBMQVStep3_local(n, no), SIZE_0, SIZE_MAX, + &Qb, &K, &Va, &Vb, &t, &block0, &sa, &block1, &stack); + // проверить certb + code = certb->val((octet*)Qb, s->params, certb->data, certb->len); + ERR_CALL_CHECK(code); + if (!qrFrom(ecX(Qb), (octet*)Qb, s->ec->f, stack) || + !qrFrom(ecY(Qb, n), (octet*)Qb + no, s->ec->f, stack) || + !ecpIsOnA(Qb, s->ec, stack)) + return ERR_BAD_CERT; + // Vb <- in, Vb \in E*? + if (!qrFrom(ecX(Vb), in, s->ec->f, stack) || + !qrFrom(ecY(Vb, n), in + no, s->ec->f, stack) || + !ecpIsOnA(Vb, s->ec, stack)) + return ERR_BAD_POINT; + // ua <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // Va <- ua G + if (!ecMulA(Va, s->ec->base, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo((octet*)Va, ecX(Va), s->ec->f, stack); + qrTo((octet*)Va + no, ecY(Va, n), s->ec->f, stack); + // t <- _2l || _2l)>_l + beltHashStart(stack); + beltHashStepH(Va, no, stack); + beltHashStepH(in, no, stack); + beltHashStepG2((octet*)t, no / 2, stack); + wwFrom(t, t, no / 2); + // out <- _4l + memCopy(out, Va, 2 * no); + // sa <- (ua - (2^l + t)da) \mod q + zzMul(sa, t, n / 2, s->d, n, stack); + sa[n + n / 2] = zzAdd2(sa + n / 2, s->d, n); + zzMod(sa, sa, n + n / 2 + 1, s->ec->order, n, stack); + zzSubMod(sa, s->u, sa, s->ec->order, n); + // K <- sa(Vb - (2^l + t)Qb), K == O => K <- G + t[n / 2] = 1; + if (!ecMulA(Qb, Qb, s->ec, t, n / 2 + 1, stack)) + return ERR_BAD_PARAMS; + if (!ecpSubAA(Vb, Vb, Qb, s->ec, stack)) + qrTo(K, s->ec->base, s->ec->f, stack); + else + { + if (!ecMulA(Vb, Vb, s->ec, sa, n, stack)) + return ERR_BAD_PARAMS; + qrTo(K, ecX(Vb), s->ec->f, stack); + } + // K <- beltHash(_2l || certa || certb || helloa || hellob) + beltHashStart(stack); + beltHashStepH(K, no, stack); + beltHashStepH(s->cert->data, s->cert->len, stack); + beltHashStepH(certb->data, certb->len, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + beltHashStepG(K, stack); + // K0 <- beltKRP(K, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, K, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(K, 1^96, 1) + if (s->settings->kca || s->settings->kcb) + { + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + } + // Ta <- beltMAC(0^128, K1), ...|| out <- Ta + if (s->settings->kca) + { + block0[0] = 0; + beltMACStart(stack, s->K1, 32); + beltMACStepA(block0, 16, stack); + beltMACStepG(out + 2 * no, stack); + } + // завершение + return ERR_OK; +} + +static size_t bakeBMQVStep3_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBMQVStep3_local(n, O_OF_W(n)), + utilMax(9, + f_deep, + ecpIsOnA_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n), + ecpSubAA_deep(n, f_deep), + beltKRP_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBMQVStep4_local(n, no)\ +/* Qa */ O_OF_W(2 * n),\ +/* K */ no | SIZE_HI,\ +/* Va */ O_OF_W(2 * n),\ +/* t */ O_OF_W(n / 2 + 1),\ +/* block0 */ (size_t)16 | SIZE_HI,\ +/* sb */ O_OF_W(n + n / 2 + 1),\ +/* block1 */ (size_t)16 | SIZE_HI + +err_t bakeBMQVStep4(octet out[], const octet in[], const bake_cert* certa, + void* state) +{ + err_t code; + bake_bmqv_st* s = (bake_bmqv_st*)state; + size_t n, no; + word* Qa; /* [2 * n] */ + word* Va; /* [2 * n] */ + word* t; /* [n / 2 + 1] */ + word* sb; /* [n + n / 2 + 1] */ + octet* K; /* [no] (|Qa) */ + octet* block0; /* [16] (|t) */ + octet* block1; /* [16] (|sb) */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bmqv_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, 2 * no + (s->settings->kca ? 8u : 0)) || + !memIsValid(out, s->settings->kcb ? 8u : 0) || + !memIsValid(certa, sizeof(bake_cert)) || + !memIsValid(certa->data, certa->len) || + certa->val == 0) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBMQVStep4_local(n, no), SIZE_0, SIZE_MAX, + &Qa, &K, &Va, &t, &block0, &sb, &block1, &stack); + // проверить certa + code = certa->val((octet*)Qa, s->params, certa->data, certa->len); + ERR_CALL_CHECK(code); + if (!qrFrom(ecX(Qa), (octet*)Qa, s->ec->f, stack) || + !qrFrom(ecY(Qa, n), (octet*)Qa + no, s->ec->f, stack) || + !ecpIsOnA(Qa, s->ec, stack)) + return ERR_BAD_CERT; + // Va <- in, Va \in E*? + if (!qrFrom(ecX(Va), in, s->ec->f, stack) || + !qrFrom(ecY(Va, n), in + no, s->ec->f, stack) || + !ecpIsOnA(Va, s->ec, stack)) + return ERR_BAD_POINT; + // t <- _2l || _2l)>_l + beltHashStart(stack); + beltHashStepH(in, no, stack); + beltHashStepH(s->Vb, no, stack); + beltHashStepG2((octet*)t, no / 2, stack); + wwFrom(t, t, no / 2); + // sb <- (ub - (2^l + t)db) \mod q + zzMul(sb, t, n / 2, s->d, n, stack); + sb[n + n / 2] = zzAdd2(sb + n / 2, s->d, n); + zzMod(sb, sb, n + n / 2 + 1, s->ec->order, n, stack); + zzSubMod(sb, s->u, sb, s->ec->order, n); + // K <- sb(Va - (2^l + t)Qa), K == O => K <- G + t[n / 2] = 1; + if (!ecMulA(Qa, Qa, s->ec, t, n / 2 + 1, stack)) + return ERR_BAD_PARAMS; + if (!ecpSubAA(Va, Va, Qa, s->ec, stack)) + qrTo(K, s->ec->base, s->ec->f, stack); + else + { + if (!ecMulA(Va, Va, s->ec, sb, n, stack)) + return ERR_BAD_PARAMS; + qrTo(K, ecX(Va), s->ec->f, stack); + } + // K <- beltHash(_2l || certa || certb || helloa || hellob) + beltHashStart(stack); + beltHashStepH(K, no, stack); + beltHashStepH(certa->data, certa->len, stack); + beltHashStepH(s->cert->data, s->cert->len, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + beltHashStepG(K, stack); + // K0 <- beltKRP(K, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, K, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(K, 1^96, 1) + if (s->settings->kca || s->settings->kcb) + { + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + } + // Ta == beltMAC(0^128, K1)? + if (s->settings->kca) + { + block0[0] = 0; + beltMACStart(stack, s->K1, 32); + beltMACStepA(block0, 16, stack); + if (!beltMACStepV(in + 2 * no, stack)) + return ERR_AUTH; + } + // Tb <- beltMAC(1^128, K1)? + if (s->settings->kcb) + { + beltMACStart(stack, s->K1, 32); + beltMACStepA(block1, 16, stack); + beltMACStepG(out, stack); + } + // завершение + return ERR_OK; +} + +static size_t bakeBMQVStep4_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBMQVStep4_local(n, O_OF_W(n)), + utilMax(9, + f_deep, + ecpIsOnA_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n), + ecpSubAA_deep(n, f_deep), + beltKRP_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBMQVStep5_local()\ +/* block1 */ (size_t)16 + +err_t bakeBMQVStep5(const octet in[8], void* state) +{ + bake_bmqv_st* s = (bake_bmqv_st*)state; + octet* block1; /* [16] */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bmqv_st)) || !memIsValid(in, 8)) + return ERR_BAD_INPUT; + if (!s->settings->kcb) + return ERR_BAD_LOGIC; + // разметить стек + memSlice(s->stack, + bakeBMQVStep5_local(), SIZE_0, SIZE_MAX, + &block1, &stack); + // Tb == beltMAC(1^128, K1)? + memSet(block1, 0xFF, 16); + beltMACStart(stack, s->K1, 32); + beltMACStepA(block1, 16, stack); + if (!beltMACStepV(in, stack)) + return ERR_AUTH; + // завершение + return ERR_OK; +} + +static size_t bakeBMQVStep5_deep() +{ + return memSliceSize( + bakeBMQVStep5_local(), + beltMAC_keep(), + SIZE_MAX); +} + +err_t bakeBMQVStepG(octet key[32], void* state) +{ + bake_bmqv_st* s = (bake_bmqv_st*)state; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bmqv_st)) || !ecIsOperable(s->ec) || + !memIsValid(key, 32)) + return ERR_BAD_INPUT; + // key <- K0 + memCopy(key, s->K0, 32); + // завершение + return ERR_OK; +} + +static size_t bakeBMQV_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return utilMax(5, + bakeBMQVStart_deep(n, f_deep), + bakeBMQVStep2_deep(n, f_deep, ec_d, ec_deep), + bakeBMQVStep3_deep(n, f_deep, ec_d, ec_deep), + bakeBMQVStep4_deep(n, f_deep, ec_d, ec_deep), + bakeBMQVStep5_deep()); +} + +/* +******************************************************************************* +Выполнение BMQV +******************************************************************************* +*/ + +err_t bakeBMQVRunB(octet key[32], const bign_params* params, + const bake_settings* settings, const octet privkeyb[], + const bake_cert* certb, const bake_cert* certa, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [l / 2 + 8] */ + octet* out; /* [l / 2] */ + void* state; /* [bakeBMQV_keep(l)] */ + // проверить key + if (!memIsValid(key, 32)) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + params->l / 2 + 8, + params->l / 2, + bakeBMQV_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBMQVStart(state, params, settings, privkeyb, certb); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 2 + code = bakeBMQVStep2(out, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 2, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 4 + code = read(&len, in, params->l / 2 + (settings->kca ? 8u : 0), file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBMQVStep4(out, in, certa, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + if (settings->kcb) + { + code = write(&len, out, 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBMQVStepG(key, state); + blobClose(blob); + return code; +} + +err_t bakeBMQVRunA(octet key[32], const bign_params* params, + const bake_settings* settings, const octet privkeya[], + const bake_cert* certa, const bake_cert* certb, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [l / 2] */ + octet* out; /* [l / 2 + 8] */ + void* state; /* [bakeBMQV_keep(l)] */ + // проверить key + if (!memIsValid(key, 32)) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + params->l / 2, + params->l / 2 + 8, + bakeBMQV_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBMQVStart(state, params, settings, privkeya, certa); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 3 + code = read(&len, in, params->l / 2, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBMQVStep3(out, in, certb, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 2 + (settings->kca ? 8u : 0), file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 5 + if (settings->kcb) + { + code = read(&len, in, 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBMQVStep5(in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBMQVStepG(key, state); + blobClose(blob); + return code; +} diff --git a/src/crypto/bake/bake_bpace.c b/src/crypto/bake/bake_bpace.c new file mode 100644 index 00000000..d809ca63 --- /dev/null +++ b/src/crypto/bake/bake_bpace.c @@ -0,0 +1,651 @@ +/* +******************************************************************************* +\file bake_bpace.c +\brief STB 34.101.66 (bake): the BPACE protocol +\project bee2 [cryptographic library] +\created 2014.04.14 +\version 2025.09.26 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#include "bee2/core/blob.h" +#include "bee2/core/err.h" +#include "bee2/core/mem.h" +#include "bee2/core/obj.h" +#include "bee2/core/util.h" +#include "bee2/crypto/bake.h" +#include "bee2/crypto/belt.h" +#include "bee2/math/qr.h" +#include "bee2/math/ecp.h" +#include "bee2/math/ww.h" +#include "bee2/math/zz.h" +#include "../bign/bign_lcl.h" +#include "bake_lcl.h" + +/* +******************************************************************************* +Алгоритм bakeSWU +******************************************************************************* +*/ + +#define bakeSWUEc_local(n, no)\ +/* H */ no + 16,\ +/* s */ O_OF_W(n + W_OF_O(16)) | SIZE_HI + +static void bakeSWUEc(word W[], const ec_o* ec, const octet X[], void* stack) +{ + octet* H; /* [no + 16] */ + word* s; /* [n + W_OF_O(16)] (|H) */ + // pre + ASSERT(ecIsOperable(ec)); + ASSERT(memIsValid(X, ec->f->no)); + ASSERT(wwIsValid(W, 2 * ec->f->n)); + // разметить стек + memSlice(stack, + bakeSWUEc_local(ec->f->n, ec->f->no), SIZE_0, SIZE_MAX, + &H, &s, &stack); + // H <- beltWBL(X, 0, 0) + memSetZero(H + ec->f->no, 16); + beltWBLStart(stack, H + ec->f->no, 16); + memCopy(H, X, ec->f->no); + beltWBLStepE(H, ec->f->no + 16, stack); + // s <- \bar H mod p + wwFrom(s, H, ec->f->no + 16); + zzMod(s, s, ec->f->n + W_OF_O(16), ec->f->mod, ec->f->n, stack); + // W <- ecpSWU(s) + wwTo(H, ec->f->no, s); + qrFrom(s, H, ec->f, stack); + ecpSWU(W, s, ec, stack); +} + +static size_t bakeSWUEc_deep(size_t n, size_t f_deep) +{ + return memSliceSize( + bakeSWUEc_local(n, O_OF_W(n)), + utilMax(2, + zzMod_deep(n + W_OF_O(16), n), + ecpSWU_deep(n, f_deep)), + SIZE_MAX); +} + +err_t bakeSWU(octet pt[], const bign_params* params, const octet msg[]) +{ + err_t code; + ec_o* ec; + void* state; + word* W; /* [2 * n] */ + void* stack; + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(msg, params->l / 4) || !memIsValid(pt, params->l / 2)) + return ERR_BAD_INPUT; + // создать кривую + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + // создать состояние + state = blobCreate2( + O_OF_W(2 * ec->f->n), + bakeSWUEc_deep(ec->f->n, ec->f->deep), + SIZE_MAX, + &W, &stack); + if (state == 0) + { + bignEcClose(ec); + return ERR_OUTOFMEMORY; + } + // вычислить точку + bakeSWUEc(W, ec, msg, stack); + wwTo(pt, 2 * ec->f->no, W); + // завершение + blobClose(state); + bignEcClose(ec); + return ERR_OK; +} + +/* +******************************************************************************* +Шаги протокола BPACE + +\todo Контроль последовательности выполнения шагов? +******************************************************************************* +*/ + +typedef struct +{ + bake_settings settings[1]; /*< настройки */ + octet K0[32]; /*< ключ K0 */ + octet K1[32]; /*< ключ K1 */ + octet K2[32]; /*< ключ K2 */ + ec_o* ec; /*< эллиптическая кривая */ + octet* R; /*< [no] (Ra || Rb или ecX(Va)) */ + word* W; /*< [2 * n] точка W */ + word* u; /*< [n] ua или ub */ + void* stack; /*< [bakeBPACE_deep] стек */ + mem_align_t data[]; /*< данные */ +} bake_bpace_st; + +static size_t bakeBPACE_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep); + +#define bakeBPACE_state(n, no)\ +/* R */ no,\ +/* W */ O_OF_W(2 * n),\ +/* u */ O_OF_W(n) + +size_t bakeBPACE_keep(size_t l) +{ + const size_t n = W_OF_B(2 * l); + const size_t no = O_OF_B(2 * l); + return sizeof(bake_bpace_st) + + memSliceSize( + bakeEcStart_keep(l, bakeBPACE_deep), + bakeBPACE_state(n, no), + SIZE_MAX); +} + +err_t bakeBPACEStart(void* state, const bign_params* params, + const bake_settings* settings, const octet pwd[], size_t pwd_len) +{ + err_t code; + bake_bpace_st* s = (bake_bpace_st*)state; + size_t n, no; + void* stack; + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(settings, sizeof(bake_settings)) || + !memIsNullOrValid(settings->helloa, settings->helloa_len) || + !memIsNullOrValid(settings->hellob, settings->hellob_len) || + !memIsValid(pwd, pwd_len)) + return ERR_BAD_INPUT; + if (settings->rng == 0) + return ERR_BAD_RNG; + // развернуть кривую + code = bakeEcStart(s->data, params); + ERR_CALL_CHECK(code); + memSlice(s->data, + objKeep(s->data), SIZE_0, SIZE_MAX, + &s->ec, &stack); + n = s->ec->f->n, no = s->ec->f->no; + // разметить состояние + memSlice(stack, + bakeBPACE_state(n, no), SIZE_0, SIZE_0, SIZE_MAX, + &s->R, &s->W, &s->u, &s->stack, &stack); + // загрузить настройки + memCopy(s->settings, settings, sizeof(bake_settings)); + // K2 <- beltHash(pwd) + beltHashStart(stack); + beltHashStepH(pwd, pwd_len, stack); + beltHashStepG(s->K2, stack); + // завершение + return code; +} + +static size_t bakeBPACEStart_deep() +{ + return beltHash_keep(); +} + +err_t bakeBPACEStep2(octet out[], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + size_t no; + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + no = s->ec->f->no; + if (!memIsValid(out, no / 2)) + return ERR_BAD_INPUT; + // разметить стек + stack = s->stack; + // Rb <-R {0, 1}^l + s->settings->rng(out, no / 2, s->settings->rng_state); + memCopy(s->R + no / 2, out, no / 2); + // out <- beltECB(Rb, K2) + beltECBStart(stack, s->K2, 32); + beltECBStepE(out, no / 2, stack); + // завершение + return ERR_OK; +} + +static size_t bakeBPACEStep2_deep() +{ + return beltECB_keep(); +} + +#define bakeBPACEStep3_local(n)\ +/* Va */ O_OF_W(2 * n) + +err_t bakeBPACEStep3(octet out[], const octet in[], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + size_t n, no; + word* Va; /* [2 * n] */ + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, no / 2) || + !memIsValid(out, 5 * no / 2)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBPACEStep3_local(n), SIZE_0, SIZE_MAX, + &Va, &stack); + // Rb <- beltECBDecr(Yb, K2) + memCopy(s->R + no / 2, in, no / 2); + beltECBStart(stack, s->K2, 32); + beltECBStepD(s->R + no / 2, no / 2, stack); + // Ra <-R {0, 1}^l + s->settings->rng(out, no / 2, s->settings->rng_state); + memCopy(s->R, out, no / 2); + // out ||... <- beltECBEncr(Ra, K2) + beltECBStart(stack, s->K2, 32); + beltECBStepE(out, no / 2, stack); + // W <- bakeSWU(Ra || Rb) + bakeSWUEc(s->W, s->ec, s->R, stack); + // ua <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // Va <- ua W + if (!ecMulA(Va, s->W, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + // ...|| out <- + qrTo(out + no / 2, ecX(Va), s->ec->f, stack); + qrTo(out + 3 * no / 2, ecY(Va, n), s->ec->f, stack); + // сохранить x-координату Va + memCopy(s->R, out + no / 2, no); + // завершение + return ERR_OK; +} + +static size_t bakeBPACEStep3_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBPACEStep3_local(n), + utilMax(4, + beltECB_keep(), + bakeSWUEc_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + f_deep), + SIZE_MAX); +} + +#define bakeBPACEStep4_local(n)\ +/* Va */ O_OF_W(2 * n),\ +/* K */ O_OF_W(2 * n) | SIZE_HI,\ +/* Y */ (size_t)32 | SIZE_HI,\ +/* Vb */ O_OF_W(2 * n),\ +/* block0 */ (size_t)16 | SIZE_HI,\ +/* block1 */ (size_t)16 + +err_t bakeBPACEStep4(octet out[], const octet in[], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + size_t n, no; + word* Va; /* [2 * n] */ + word* K; /* [2 * n] (|Va) */ + octet* Y; /* [32] (|K) */ + word* Vb; /* [2 * n] */ + octet* block0; /* [16] (|Vb) */ + octet* block1; /* [16] */ + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, 5 * no / 2) || + !memIsValid(out, 2 * no + (s->settings->kcb ? 8u : 0))) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBPACEStep4_local(n), SIZE_0, SIZE_MAX, + &Va, &K, &Y, &Vb, &block0, &block1, &stack); + // Va <- ... || in, Va \in E*? + if (!qrFrom(ecX(Va), in + no / 2, s->ec->f, stack) || + !qrFrom(ecY(Va, n), in + no / 2 + no, s->ec->f, stack) || + !ecpIsOnA(Va, s->ec, stack)) + return ERR_BAD_POINT; + // Ra <- beltECBDecr(in ||..., K2) + memCopy(s->R, in, no / 2); + beltECBStart(stack, s->K2, 32); + beltECBStepD(s->R, no / 2, stack); + // W <- bakeSWU(Ra || Rb) + bakeSWUEc(s->W, s->ec, s->R, stack); + // ub <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // K <- ub Va + if (!ecMulA(K, Va, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo((octet*)K, ecX(K), s->ec->f, stack); + // Vb <- ub W + if (!ecMulA(Vb, s->W, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo((octet*)ecX(Vb), ecX(Vb), s->ec->f, stack); + qrTo((octet*)ecY(Vb, n), ecY(Vb, n), s->ec->f, stack); + // Y <- beltHash(_2l || _2l || _2l || helloa || hellob) + beltHashStart(stack); + beltHashStepH(K, no, stack); + beltHashStepH(in + no / 2, no, stack); + beltHashStepH(Vb, no, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + beltHashStepG(Y, stack); + // out ||... <- + memCopy(out, ecX(Vb), no); + memCopy(out + no, ecY(Vb, n), no); + // K0 <- beltKRP(Y, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, Y, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(Y, 1^96, 1) + if (s->settings->kca || s->settings->kcb) + { + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + } + // Tb <- beltMAC(1^128, K1), ...|| out <- Tb + if (s->settings->kcb) + { + beltMACStart(stack, s->K1, 32); + beltMACStepA(block1, 16, stack); + beltMACStepG(out + 2 * no, stack); + } + // завершение + return ERR_OK; +} + +static size_t bakeBPACEStep4_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBPACEStep4_local(n), + utilMax(7, + f_deep, + beltECB_keep(), + bakeSWUEc_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + beltKRP_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBPACEStep5_local(n)\ +/* Vb */ O_OF_W(2 * n),\ +/* K */ O_OF_W(2 * n),\ +/* Y */ (size_t)32,\ +/* block0 */ (size_t)16,\ +/* block1 */ (size_t)16 + +err_t bakeBPACEStep5(octet out[], const octet in[], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + size_t n, no; + word* Vb; /* [2 * n] */ + word* K; /* [2 * n] */ + octet* Y; /* [32] */ + octet* block0; /* [16] */ + octet* block1; /* [16] */ + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, 2 * no + (s->settings->kcb ? 8u : 0)) || + !memIsValid(out, s->settings->kca ? 8u : 0)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBPACEStep5_local(n), SIZE_0, SIZE_MAX, + &Vb, &K, &Y, &block0, &block1, &stack); + // Vb <- in ||..., Vb \in E*? + if (!qrFrom(ecX(Vb), in, s->ec->f, stack) || + !qrFrom(ecY(Vb, n), in + no, s->ec->f, stack) || + !ecpIsOnA(Vb, s->ec, stack)) + return ERR_BAD_POINT; + // K <- ua Vb + if (!ecMulA(K, Vb, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo((octet*)K, ecX(K), s->ec->f, stack); + qrTo((octet*)Vb, ecX(Vb), s->ec->f, stack); + // Y <- beltHash(_2l || _2l || _2l || helloa || hellob) + beltHashStart(stack); + beltHashStepH(K, no, stack); + beltHashStepH(s->R, no, stack); + beltHashStepH(Vb, no, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + ASSERT(no >= 32); + beltHashStepG(Y, stack); + // K0 <- beltKRP(Y, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, Y, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(Y, 1^96, 1) + if (s->settings->kca || s->settings->kcb) + { + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + } + // Tb == beltMAC(1^128, K1)? + if (s->settings->kcb) + { + beltMACStart(stack, s->K1, 32); + beltMACStepA(block1, 16, stack); + if (!beltMACStepV(in + 2 * no, stack)) + return ERR_AUTH; + } + // Ta <- beltMAC(0^128, K1) + if (s->settings->kca) + { + block0[0] = 0; + beltMACStart(stack, s->K1, 32); + beltMACStepA(block0, 16, stack); + beltMACStepG(out, stack); + } + // завершение + return ERR_OK; +} + +static size_t bakeBPACEStep5_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBPACEStep5_local(n), + utilMax(5, + f_deep, + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + beltKRP_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBPACEStep6_local()\ +/* block0 */ (size_t)16 + +err_t bakeBPACEStep6(const octet in[8], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + octet* block0; /* [16] */ + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + if (!s->settings->kca) + return ERR_BAD_LOGIC; + if (!memIsValid(in, 8)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBPACEStep6_local(), SIZE_0, SIZE_MAX, + &block0, &stack); + // Ta == beltMAC(0^128, K1)? + memSetZero(block0, 16); + beltMACStart(stack, s->K1, 32); + beltMACStepA(block0, 16, stack); + if (!beltMACStepV(in, stack)) + return ERR_AUTH; + // завершение + return ERR_OK; +} + +static size_t bakeBPACEStep6_deep() +{ + return memSliceSize( + bakeBPACEStep6_local(), + beltMAC_keep(), + SIZE_MAX); +} + +err_t bakeBPACEStepG(octet key[32], void* state) +{ + bake_bpace_st* s = (bake_bpace_st*)state; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bpace_st)) || !ecIsOperable(s->ec) || + !memIsValid(key, 32)) + return ERR_BAD_INPUT; + // key <- K0 + memCopy(key, s->K0, 32); + // завершение + return ERR_OK; +} + +static size_t bakeBPACE_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return utilMax(6, + bakeBPACEStart_deep(), + bakeBPACEStep2_deep(), + bakeBPACEStep3_deep(n, f_deep, ec_d, ec_deep), + bakeBPACEStep4_deep(n, f_deep, ec_d, ec_deep), + bakeBPACEStep5_deep(n, f_deep, ec_d, ec_deep), + bakeBPACEStep6_deep()); +} + +/* +******************************************************************************* +Выполнение BPACE +******************************************************************************* +*/ + +err_t bakeBPACERunB(octet key[32], const bign_params* params, + const bake_settings* settings, const octet pwd[], size_t pwd_len, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [5 * l / 8] */ + octet* out; /* [l / 2 + 8] */ + void* state; /* [bakeBPACE_keep()] */ + // проверить key + if (!memIsValid(key, 32)) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + 5 * params->l / 8, + params->l / 2 + 8, + bakeBPACE_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBPACEStart(state, params, settings, pwd, pwd_len); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 2 + code = bakeBPACEStep2(out, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 4 + code = read(&len, in, 5 * params->l / 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBPACEStep4(out, in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 2 + (settings->kcb ? 8u : 0), file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 6 + if (settings->kca) + { + code = read(&len, in, 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBPACEStep6(in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBPACEStepG(key, state); + blobClose(blob); + return code; +} + +err_t bakeBPACERunA(octet key[32], const bign_params* params, + const bake_settings* settings, const octet pwd[], size_t pwd_len, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [l / 2 + 8] */ + octet* out; /* [5 * l / 8] */ + void* state; /* [bakeBPACE_keep()] */ + // проверить key + if (!memIsValid(key, 32)) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + params->l / 2 + 8, + 5 * params->l / 8, + bakeBPACE_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBPACEStart(state, params, settings, pwd, pwd_len); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 3 + code = read(&len, in, params->l / 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBPACEStep3(out, in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, 5 * params->l / 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 5 + code = read(&len, in, params->l / 2 + (settings->kcb ? 8u : 0), file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBPACEStep5(out, in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + if (settings->kca) + { + code = write(&len, out, 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBPACEStepG(key, state); + blobClose(blob); + return code; +} diff --git a/src/crypto/bake/bake_bsts.c b/src/crypto/bake/bake_bsts.c new file mode 100644 index 00000000..d02243b7 --- /dev/null +++ b/src/crypto/bake/bake_bsts.c @@ -0,0 +1,732 @@ +/* +******************************************************************************* +\file bake_bsts.c +\brief STB 34.101.66 (bake): the BSTS protocol +\project bee2 [cryptographic library] +\created 2014.04.14 +\version 2025.09.27 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#include "bee2/core/blob.h" +#include "bee2/core/err.h" +#include "bee2/core/mem.h" +#include "bee2/core/obj.h" +#include "bee2/core/util.h" +#include "bee2/crypto/bake.h" +#include "bee2/crypto/belt.h" +#include "bee2/math/qr.h" +#include "bee2/math/ecp.h" +#include "bee2/math/ww.h" +#include "bee2/math/zz.h" +#include "../bign/bign_lcl.h" +#include "bake_lcl.h" + +/* +******************************************************************************* +Шаги протокола BSTS + +\todo Контроль последовательности выполнения шагов? +******************************************************************************* +*/ + +typedef struct +{ + bign_params params[1]; /*< параметры */ + bake_settings settings[1]; /*< настройки */ + bake_cert cert[1]; /*< сертификат */ + octet K0[32]; /*< ключ K0 */ + octet K1[32]; /*< ключ K1 */ + octet K2[32]; /*< ключ K2 */ + ec_o* ec; /*< эллиптическая кривая */ + word* d; /*< [n] долговременный личный ключ */ + word* u; /*< [n] одноразовый личный ключ */ + word* t; /*< [n / 2 + 1] (|u) */ + word* Vb; /*< [2 * n] */ + void* stack; /*< [bakeBSTS_deep] стек */ + mem_align_t data[]; /*< данные */ +} bake_bsts_st; + +#define bakeBSTS_state(n)\ +/* d */ O_OF_W(n),\ +/* u */ O_OF_W(n),\ +/* t */ O_OF_W(n / 2 + 1) | SIZE_HI,\ +/* Vb */ O_OF_W(2 * n) + +static size_t bakeBSTS_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep); + +size_t bakeBSTS_keep(size_t l) +{ + const size_t n = W_OF_B(2 * l); + return sizeof(bake_bsts_st) + + memSliceSize( + bakeEcStart_keep(l, bakeBSTS_deep), + bakeBSTS_state(n), + SIZE_MAX); +} + +#define bakeBSTSStart_local(n)\ +/* Q */ O_OF_W(2 * n) + +err_t bakeBSTSStart(void* state, const bign_params* params, + const bake_settings* settings, const octet privkey[], + const bake_cert* cert) +{ + err_t code; + bake_bsts_st* s = (bake_bsts_st*)state; + size_t n, no; + word* Q; /* [2 * n] */ + void* stack; + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(settings, sizeof(bake_settings)) || + settings->kca != TRUE || settings->kcb != TRUE || + !memIsNullOrValid(settings->helloa, settings->helloa_len) || + !memIsNullOrValid(settings->hellob, settings->hellob_len) || + !memIsValid(privkey, params->l / 4) || + !memIsValid(cert, sizeof(bake_cert)) || + !memIsValid(cert->data, cert->len) || + cert->val == 0) + return ERR_BAD_INPUT; + if (settings->rng == 0) + return ERR_BAD_RNG; + // развернуть кривую + code = bakeEcStart(s->data, params); + ERR_CALL_CHECK(code); + memSlice(s->data, + objKeep(s->data), SIZE_0, SIZE_MAX, + &s->ec, &stack); + n = s->ec->f->n, no = s->ec->f->no; + // разметить состояние и стек + memSlice(stack, + bakeBSTS_state(n), SIZE_0, + bakeBSTSStart_local(n), SIZE_0, SIZE_MAX, + &s->d, &s->u, &s->t, &s->Vb, &s->stack, &Q, &stack); + // сохранить параметры + memCopy(s->params, params, sizeof(bign_params)); + // сохранить настройки + memCopy(s->settings, settings, sizeof(bake_settings)); + // загрузить личный ключ + wwFrom(s->d, privkey, no); + // проверить сертификат и его открытый ключ + code = cert->val((octet*)Q, params, cert->data, cert->len); + ERR_CALL_CHECK(code); + if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) || + !qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) || + !ecpIsOnA(Q, s->ec, stack)) + return ERR_BAD_CERT; + // сохранить сертификат + memCopy(s->cert, cert, sizeof(bake_cert)); + // завершение + return code; +} + +static size_t bakeBSTSStart_deep(size_t n, size_t f_deep) +{ + return memSliceSize( + bakeBSTSStart_local(n), + utilMax(2, + f_deep, + ecpIsOnA_deep(n, f_deep)), + SIZE_MAX); +} + + +#define bakeBSTSStep2_local(n)\ +/* Vb */ O_OF_W(2 * n) + +err_t bakeBSTSStep2(octet out[], void* state) +{ + bake_bsts_st* s = (bake_bsts_st*)state; + size_t n, no; + void* stack; + // обработать входные данные + if (!memIsValid(s, sizeof(bake_bsts_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(out, 2 * no)) + return ERR_BAD_INPUT; + // разметить стек + stack = s->stack; + // ub <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // Vb <- ub G + if (!ecMulA(s->Vb, s->ec->base, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + // out <- + qrTo(out, ecX(s->Vb), s->ec->f, stack); + qrTo(out + no, ecY(s->Vb, n), s->ec->f, stack); + // завершение + return ERR_OK; +} + +static size_t bakeBSTSStep2_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return utilMax(2, + f_deep, + ecMulA_deep(n, ec_d, ec_deep, n)); +} + +#define bakeBSTSStep3_local(n, no)\ +/* Va */ O_OF_W(2 * n),\ +/* K */ no | SIZE_HI,\ +/* t */ O_OF_W(n / 2 + 1),\ +/* sa */ O_OF_W(n + n / 2 + 1),\ +/* block0 */ (size_t)16,\ +/* block1 */ (size_t)16 + +err_t bakeBSTSStep3(octet out[], const octet in[], void* state) +{ + bake_bsts_st* s = (bake_bsts_st*)state; + size_t n, no; + word* Va; /* [2 * n] */ + word* t; /* [n / 2 + 1] */ + word* sa; /* [n + n / 2 + 1] */ + octet* K; /* [no] (|Va) */ + octet* block0; /* [16] */ + octet* block1; /* [16] */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bsts_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (!memIsValid(in, 2 * no) || + !memIsValid(out, 3 * no + s->cert->len + 8)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBSTSStep3_local(n, no), SIZE_0, SIZE_MAX, + &Va, &K, &t, &sa, &block0, &block1, &stack); + // Vb <- in, Vb \in E*? + if (!qrFrom(ecX(s->Vb), in, s->ec->f, stack) || + !qrFrom(ecY(s->Vb, n), in + no, s->ec->f, stack) || + !ecpIsOnA(s->Vb, s->ec, stack)) + return ERR_BAD_POINT; + // ua <-R {1, 2, ..., q - 1} + if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng, + s->settings->rng_state)) + return ERR_BAD_RNG; + // Va <- ua G + if (!ecMulA(Va, s->ec->base, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo((octet*)Va, ecX(Va), s->ec->f, stack); + qrTo((octet*)Va + no, ecY(Va, n), s->ec->f, stack); + // t <- _2l || _2l)>_l + beltHashStart(stack); + beltHashStepH(Va, no, stack); + beltHashStepH(in, no, stack); + beltHashStepG2((octet*)t, no / 2, stack); + wwFrom(t, t, no / 2); + // out ||.. <- _4l + memCopy(out, Va, 2 * no); + // sa <- (ua - (2^l + t)da) \mod q + zzMul(sa, t, n / 2, s->d, n, stack); + sa[n + n / 2] = zzAdd2(sa + n / 2, s->d, n); + zzMod(sa, sa, n + n / 2 + 1, s->ec->order, n, stack); + zzSubMod(sa, s->u, sa, s->ec->order, n); + // ..|| out ||.. <- sa || certa + wwTo(out + 2 * no, no, sa); + memCopy(out + 3 * no, s->cert->data, s->cert->len); + // K <- beltHash(_2l || helloa || hellob) + if (!ecMulA(Va, s->Vb, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo(K, ecX(Va), s->ec->f, stack); + beltHashStart(stack); + beltHashStepH(K, no, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + beltHashStepG(K, stack); + // K0 <- beltKRP(K, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, K, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(K, 1^96, 1) + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + // K2 <- beltKRP(K, 1^96, 2) + block0[0] = 2; + beltKRPStepG(s->K2, 32, block0, stack); + // ..|| out ||.. <- beltCFBEncr(sa || certa) + block0[0] = 0; + beltCFBStart(stack, s->K2, 32, block0); + beltCFBStepE(out + 2 * no, no + s->cert->len, stack); + // ..|| out <- beltMAC(beltCFBEncr(sa || certa) || 0^128) + beltMACStart(stack, s->K1, 32); + beltMACStepA(out + 2 * no, no + s->cert->len, stack); + beltMACStepA(block0, 16, stack); + beltMACStepG(out + 3 * no + s->cert->len, stack); + // сохранить t + wwCopy(s->t, t, n / 2); + s->t[n / 2] = 1; + // завершение + return ERR_OK; +} + +static size_t bakeBSTSStep3_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBSTSStep3_local(n, O_OF_W(n)), + utilMax(9, + f_deep, + ecpIsOnA_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n), + beltKRP_keep(), + beltCFB_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBSTSStep4_local(n, no)\ +/* Va */ O_OF_W(2 * n),\ +/* Qa */ O_OF_W(2 * n),\ +/* K */ no | SIZE_HI,\ +/* t */ O_OF_W(n / 2 + 1),\ +/* sa */ O_OF_W(n),\ +/* sb */ O_OF_W(n + n / 2 + 1),\ +/* block0 */ (size_t)16,\ +/* block1 */ (size_t)16 + +err_t bakeBSTSStep4(octet out[], const octet in[], size_t in_len, + bake_certval_i vala, void* state) +{ + err_t code; + bake_bsts_st* s = (bake_bsts_st*)state; + size_t n, no; + word* Va; /* [2 * n] */ + word* Qa; /* [2 * n] */ + word* t; /* [n / 2 + 1] */ + word* sa; /* [n] */ + word* sb; /* [n + n / 2 + 1] */ + octet* K; /* [no] */ + octet* block0; /* [16] */ + octet* block1; /* [16] */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bsts_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (in_len <= 3 * no + 8 || + !memIsValid(in, in_len) || + vala == 0 || + !memIsValid(out, no + s->cert->len + 8)) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBSTSStep4_local(n, no), SIZE_0, SIZE_MAX, + &Va, &Qa, &K, &t, &sa, &sb, &block0, &block1, &stack); + // Va <- in, Va \in E*? + if (!qrFrom(ecX(Va), in, s->ec->f, stack) || + !qrFrom(ecY(Va, n), in + no, s->ec->f, stack) || + !ecpIsOnA(Va, s->ec, stack)) + return ERR_BAD_POINT; + // K <- beltHash(_2l || helloa || hellob) + if (!ecMulA(Qa, Va, s->ec, s->u, n, stack)) + return ERR_BAD_PARAMS; + qrTo(K, ecX(Qa), s->ec->f, stack); + beltHashStart(stack); + beltHashStepH(K, no, stack); + if (s->settings->helloa) + beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack); + if (s->settings->hellob) + beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack); + beltHashStepG(K, stack); + // K0 <- beltKRP(K, 1^96, 0) + memSetZero(block0, 16); + memSet(block1, 0xFF, 16); + beltKRPStart(stack, K, 32, block1); + beltKRPStepG(s->K0, 32, block0, stack); + // K1 <- beltKRP(K, 1^96, 1) + block0[0] = 1; + beltKRPStepG(s->K1, 32, block0, stack); + // K2 <- beltKRP(K, 1^96, 2) + block0[0] = 2; + beltKRPStepG(s->K2, 32, block0, stack); + // Ta == beltMAC(Ya || 0^128, K1)? + block0[0] = 0; + beltMACStart(stack, s->K1, 32); + beltMACStepA(in + 2 * no, in_len - 2 * no - 8, stack); + beltMACStepA(block0, 16, stack); + if (!beltMACStepV(in + in_len - 8, stack)) + return ERR_AUTH; + // обработать Ya = [in_len - 2 * no - 8]in + in_len -= 2 * no + 8; + { + blob_t Ya; + // sa || certa <- beltCFBDecr(Ya, K2, 0^128) + if ((Ya = blobCreate(in_len)) == 0) + return ERR_OUTOFMEMORY; + memCopy(Ya, in + 2 * no, in_len); + beltCFBStart(stack, s->K2, 32, block0); + beltCFBStepD(Ya, in_len, stack); + // sa \in {0, 1,..., q - 1}? + wwFrom(sa, Ya, no); + if (wwCmp(sa, s->ec->order, n) >= 0) + { + blobClose(Ya); + return ERR_AUTH; + } + // проверить certa + code = vala((octet*)Qa, s->params, (octet*)Ya + no, in_len - no); + ERR_CALL_HANDLE(code, blobClose(Ya)); + if (!qrFrom(ecX(Qa), (octet*)Qa, s->ec->f, stack) || + !qrFrom(ecY(Qa, n), (octet*)Qa + no, s->ec->f, stack) || + !ecpIsOnA(Qa, s->ec, stack)) + code = ERR_BAD_CERT; + blobClose(Ya); + ERR_CALL_CHECK(code); + } + // t <- _2l || _2l)>_l + beltHashStart(stack); + beltHashStepH(in, no, stack); + qrTo((octet*)s->Vb, s->Vb, s->ec->f, stack); + beltHashStepH(s->Vb, no, stack); + beltHashStepG2((octet*)t, no / 2, stack); + wwFrom(t, t, no / 2); + // sa G + (2^l + t)Qa == Va? + t[n / 2] = 1; + if (!ecAddMulA(Qa, s->ec, stack, 2, s->ec->base, sa, n, Qa, t, n / 2 + 1)) + return ERR_BAD_PARAMS; + if (!wwEq(Qa, Va, 2 * n)) + return ERR_AUTH; + // sb <- (ub - (2^l + t)db) \mod q + zzMul(sb, t, n / 2, s->d, n, stack); + sb[n + n / 2] = zzAdd2(sb + n / 2, s->d, n); + zzMod(sb, sb, n + n / 2 + 1, s->ec->order, n, stack); + zzSubMod(sb, s->u, sb, s->ec->order, n); + // out ||.. <- beltCFBEncr(sb || certb) + wwTo(out, no, sb); + memCopy(out + no, s->cert->data, s->cert->len); + beltCFBStart(stack, s->K2, 32, block1); + beltCFBStepE(out, no + s->cert->len, stack); + // .. || out <- beltMAC(beltCFBEncr(sb || certb) || 1^128) + beltMACStart(stack, s->K1, 32); + beltMACStepA(out, no + s->cert->len, stack); + beltMACStepA(block1, 16, stack); + beltMACStepG(out + no + s->cert->len, stack); + // завершение + return ERR_OK; +} + +static size_t bakeBSTSStep4_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBSTSStep4_local(n, O_OF_W(n)), + utilMax(10, + f_deep, + ecpIsOnA_deep(n, f_deep), + ecMulA_deep(n, ec_d, ec_deep, n), + beltHash_keep(), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n), + ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1), + beltKRP_keep(), + beltCFB_keep(), + beltMAC_keep()), + SIZE_MAX); +} + +#define bakeBSTSStep5_local(n)\ +/* Qb */ O_OF_W(2 * n),\ +/* sb */ O_OF_W(n),\ +/* block1 */ (size_t)16 + +err_t bakeBSTSStep5(const octet in[], size_t in_len, bake_certval_i valb, + void* state) +{ + err_t code; + bake_bsts_st* s = (bake_bsts_st*)state; + size_t n, no; + word* Qb; /* [2 * n] */ + word* sb; /* [n] */ + octet* block1; /* [16] */ + void* stack; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bsts_st)) || !ecIsOperable(s->ec)) + return ERR_BAD_INPUT; + n = s->ec->f->n, no = s->ec->f->no; + if (in_len <= no + 8 || + !memIsValid(in, in_len) || + valb == 0) + return ERR_BAD_INPUT; + // разметить стек + memSlice(s->stack, + bakeBSTSStep5_local(n), SIZE_0, SIZE_MAX, + &Qb, &sb, &block1, &stack); + // Tb == beltMAC(Yb || 1^128, K1)? + memSet(block1, 0xFF, 16); + beltMACStart(stack, s->K1, 32); + beltMACStepA(in, in_len - 8, stack); + beltMACStepA(block1, 16, stack); + if (!beltMACStepV(in + in_len - 8, stack)) + return ERR_AUTH; + // обработать Yb = [in_len - 8]in + in_len -= 8; + { + blob_t Yb; + // sb || certb <- beltCFBDecr(Yb, K2, 1^128) + if ((Yb = blobCreate(in_len)) == 0) + return ERR_OUTOFMEMORY; + memCopy(Yb, in, in_len); + beltCFBStart(stack, s->K2, 32, block1); + beltCFBStepD(Yb, in_len, stack); + // sb \in {0, 1,..., q - 1}? + wwFrom(sb, Yb, no); + if (wwCmp(sb, s->ec->order, n) >= 0) + { + blobClose(Yb); + return ERR_AUTH; + } + // проверить certa + code = valb((octet*)Qb, s->params, (octet*)Yb + no, in_len - no); + ERR_CALL_HANDLE(code, blobClose(Yb)); + if (!qrFrom(ecX(Qb), (octet*)Qb, s->ec->f, stack) || + !qrFrom(ecY(Qb, n), (octet*)Qb + no, s->ec->f, stack) || + !ecpIsOnA(Qb, s->ec, stack)) + code = ERR_BAD_CERT; + blobClose(Yb); + ERR_CALL_CHECK(code); + } + // sb G + (2^l + t)Qa == Vb? + if (!ecAddMulA(Qb, s->ec, stack, 2, s->ec->base, sb, n, + Qb, s->t, n / 2 + 1)) + return ERR_BAD_PARAMS; + if (!wwEq(Qb, s->Vb, 2 * n)) + return ERR_AUTH; + // завершение + return ERR_OK; +} + +static size_t bakeBSTSStep5_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return memSliceSize( + bakeBSTSStep5_local(n), + utilMax(5, + beltMAC_keep(), + beltCFB_keep(), + f_deep, + ecpIsOnA_deep(n, f_deep), + ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)), + SIZE_MAX); +} + +err_t bakeBSTSStepG(octet key[32], void* state) +{ + bake_bsts_st* s = (bake_bsts_st*)state; + // проверить входные данные + if (!memIsValid(s, sizeof(bake_bsts_st)) || !ecIsOperable(s->ec) || + !memIsValid(key, 32)) + return ERR_BAD_INPUT; + // key <- K0 + memCopy(key, s->K0, 32); + // завершение + return ERR_OK; +} + +static size_t bakeBSTS_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep) +{ + return utilMax(5, + bakeBSTSStart_deep(n, f_deep), + bakeBSTSStep2_deep(n, f_deep, ec_d, ec_deep), + bakeBSTSStep3_deep(n, f_deep, ec_d, ec_deep), + bakeBSTSStep4_deep(n, f_deep, ec_d, ec_deep), + bakeBSTSStep5_deep(n, f_deep, ec_d, ec_deep)); +} + +/* +******************************************************************************* +Выполнение BSTS +******************************************************************************* +*/ + +err_t bakeBSTSRunB(octet key[32], const bign_params* params, + const bake_settings* settings, const octet privkeyb[], + const bake_cert* certb, bake_certval_i vala, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [512] */ + octet* out; /* [MAX2(l / 2, l / 4 + certb->len + 8)] */ + void* state; /* [bakeBSTS_keep(l)] */ + // проверить входные данные + if (!memIsValid(key, 32) || + !memIsValid(certb, sizeof(bake_cert))) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + (size_t)512, + MAX2(params->l / 2, params->l / 4 + certb->len + 8), + bakeBSTS_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBSTSStart(state, params, settings, privkeyb, certb); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 2 + code = bakeBSTSStep2(out, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 2, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 4: прочитать блок M2 + code = read(&len, in, 512, file); + // шаг 4: M2 из одного блока? + if (code == ERR_MAX) + { + code = bakeBSTSStep4(out, in, len, vala, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 4 + certb->len + 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // шаг 4: ошибка при чтении + else if (code != ERR_OK) + { + blobClose(blob); + return code; + } + // шаг 4: обработать M2 из нескольких блоков + else + { + blob_t M2 = 0; + while (code == ERR_OK) + { + if ((M2 = blobResize(M2, blobSize(M2) + len)) == 0) + { + blobClose(blob); + return ERR_OUTOFMEMORY; + } + memCopy((octet*)M2 + blobSize(M2) - len, in, len); + code = read(&len, in, 512, file); + } + if (code != ERR_MAX) + { + blobClose(M2); + blobClose(blob); + return code; + } + if ((M2 = blobResize(M2, blobSize(M2) + len)) == 0) + { + blobClose(blob); + return ERR_OUTOFMEMORY; + } + memCopy((octet*)M2 + blobSize(M2) - len, in, len); + code = bakeBSTSStep4(out, M2, blobSize(M2), vala, state); + blobClose(M2); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, params->l / 4 + certb->len + 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBSTSStepG(key, state); + blobClose(blob); + return code; +} + +err_t bakeBSTSRunA(octet key[32], const bign_params* params, + const bake_settings* settings, const octet privkeya[], + const bake_cert* certa, bake_certval_i valb, + read_i read, write_i write, void* file) +{ + err_t code; + size_t len; + // блоб + blob_t blob; + octet* in; /* [MAX2(512, l / 2)] */ + octet* out; /* [3 * l / 4 + certa->len + 8] */ + void* state; /* [bakeBSTS_keep(l)] */ + // проверить входные данные + if (!memIsValid(key, 32) || + !memIsValid(certa, sizeof(bake_cert))) + return ERR_BAD_INPUT; + // создать блоб + if (params->l != 128 && params->l != 192 && params->l != 256) + return ERR_BAD_PARAMS; + blob = blobCreate2( + MAX2(512, params->l / 2), + 3 * params->l / 4 + certa->len + 8, + bakeBSTS_keep(params->l), + SIZE_MAX, + &in, &out, &state); + if (blob == 0) + return ERR_OUTOFMEMORY; + // старт + code = bakeBSTSStart(state, params, settings, privkeya, certa); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 3 + code = read(&len, in, params->l / 2, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = bakeBSTSStep3(out, in, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + code = write(&len, out, 3 * params->l / 4 + certa->len + 8, file); + ERR_CALL_HANDLE(code, blobClose(blob)); + // шаг 5: прочитать блок M3 + code = read(&len, in, 512, file); + // шаг 5: M3 из одного блока? + if (code == ERR_MAX) + { + code = bakeBSTSStep5(in, len, valb, state); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // шаг 5: ошибка при чтении + else if (code != ERR_OK) + { + blobClose(blob); + return code; + } + // шаг 5: обработать M3 из нескольких блоков + else + { + blob_t M3 = 0; + while (code == ERR_OK) + { + if ((M3 = blobResize(M3, blobSize(M3) + len)) == 0) + { + blobClose(blob); + return ERR_OUTOFMEMORY; + } + memCopy((octet*)M3 + blobSize(M3) - len, in, len); + code = read(&len, in, 512, file); + } + if (code != ERR_MAX) + { + blobClose(M3); + blobClose(blob); + return code; + } + if ((M3 = blobResize(M3, blobSize(M3) + len)) == 0) + { + blobClose(blob); + return ERR_OUTOFMEMORY; + } + memCopy((octet*)M3 + blobSize(M3) - len, in, len); + code = bakeBSTSStep5(M3, blobSize(M3), valb, state); + blobClose(M3); + ERR_CALL_HANDLE(code, blobClose(blob)); + } + // завершение + code = bakeBSTSStepG(key, state); + blobClose(blob); + return code; +} diff --git a/src/crypto/bake/bake_lcl.h b/src/crypto/bake/bake_lcl.h new file mode 100644 index 00000000..c1d69788 --- /dev/null +++ b/src/crypto/bake/bake_lcl.h @@ -0,0 +1,84 @@ +/* +******************************************************************************* +\file bake_lcl.h +\brief STB 34.101.66 (bake): local declarations +\project bee2 [cryptographic library] +\created 2014.04.03 +\version 2025.09.25 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#ifndef __BEE2_BAKE_LCL_H +#define __BEE2_BAKE_LCL_H + +#include "bee2/crypto/bign.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +******************************************************************************* +Эллиптические кривые + +В Bake используются эллиптические кривые Bign (СТБ 34.101.45). Описание кривой +развертывается в состоянии протокола, а не во внешнем блобе, как в Bign. +После описания кривой могут следовать поля состояния проткола переменной длины, +а за ними располагаться стек. Потребности в стеке указываются через функцию +интерфейса bake_ec_deep_i. Длина состояния с учетом стека определяется +с помощью функции bakeEcStart_keep(). Единожды подготовив память нужной длины, +можно полностью выполнить на ней весь протокол. +******************************************************************************* +*/ + + +/*! \brief Потребности в стеке + + Определяется глубина стека, который требуется стороне протокола + для работы с эллиптической кривой, описываемой объясненными ниже + размерностями n, f_deep, ec_d, ec_deep. + \remark При расчете глубины не следует учитывать память для + размещения описаний базового поля и эллиптической кривой. +*/ + +typedef size_t(*bake_ec_deep_i)( + size_t n, /*!< [in] число слов для хранения элемента поля */ + size_t f_deep, /*!< [in] глубина стека базового поля */ + size_t ec_d, /*!< [in] число проективных координат */ + size_t ec_deep /*!< [in] глубина стека эллиптической кривой */ + ); + +/*! \brief Длина состояния + + Возвращается длина состояния (в октетах) высокоуровневой функции, + которая работает на уровне стойкости l и имеет потребности в стеке deep. + \pre l == 128 || l == 192 || l == 256. + \return Длина состояния. + \remark Состояние включает как локальные переменные, так и стек. +*/ +size_t bakeEcStart_keep( + size_t l, /*!< [in] уровень стойкости */ + bake_ec_deep_i deep /*!< [in] потребности в стековой памяти */ +); + +/*! \brief Развертывание эллиптической кривой + + По долговременным параметрам params по адресу state формируется описание + эллиптической кривой. + \pre bignParamsCheck(params) == ERR_OK. + \return ERR_OK, если кривая успешно развернута, и код ошибки в противном + случае. +*/ +err_t bakeEcStart( + void* state, /*!< [out] состояние */ + const bign_params* params /*!< [in] долговременные параметры */ +); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __BEE2_BAKE_LCL_H */ diff --git a/src/crypto/bign/bign_lcl.c b/src/crypto/bake/bake_misc.c similarity index 51% rename from src/crypto/bign/bign_lcl.c rename to src/crypto/bake/bake_misc.c index 9bf5dd67..79274018 100644 --- a/src/crypto/bign/bign_lcl.c +++ b/src/crypto/bake/bake_misc.c @@ -1,90 +1,69 @@ /* ******************************************************************************* -\file bign_lcl.c -\brief STB 34.101.45 (bign): local definitions +\file bake_misc.c +\brief STB 34.101.66 (bake): miscellaneous (curves, KDF) \project bee2 [cryptographic library] -\created 2012.04.27 -\version 2023.09.19 +\created 2014.04.14 +\version 2025.09.25 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ +#include "bee2/core/blob.h" #include "bee2/core/err.h" #include "bee2/core/mem.h" +#include "bee2/core/obj.h" #include "bee2/core/util.h" -#include "bee2/math/gfp.h" +#include "bee2/crypto/bake.h" +#include "bee2/crypto/belt.h" #include "bee2/math/ecp.h" +#include "bee2/math/gfp.h" #include "bee2/math/ww.h" #include "bee2/math/zz.h" -#include "bign_lcl.h" - -/* -******************************************************************************* -Проверка работоспособности -******************************************************************************* -*/ - -bool_t bignIsOperable(const bign_params* params) -{ - size_t no; - // pre - ASSERT(memIsValid(params, sizeof(bign_params))); - // корректный уровень стойкости? - // p mod 4 == 3? q mod 2 == 1? - // p и q -- 2l-битовые? - // a != 0? b != 0? - // неиспользуемые октеты обнулены? - return - (params->l == 128 || params->l == 192 || params->l == 256) && - (no = O_OF_B(2 * params->l)) && - params->p[0] % 4 == 3 && params->q[0] % 2 == 1 && - params->p[no - 1] >= 128 && params->q[no - 1] >= 128 && - memIsZero(params->p + no, sizeof(params->p) - no) && - !memIsZero(params->a, no) && - !memIsZero(params->b, no) && - memIsZero(params->a + no, sizeof(params->a) - no) && - memIsZero(params->b + no, sizeof(params->b) - no) && - memIsZero(params->q + no, sizeof(params->q) - no) && - memIsZero(params->yG + no, sizeof(params->yG) - no); -} +#include "../bign/bign_lcl.h" +#include "bake_lcl.h" /* ******************************************************************************* -Создание эллиптической кривой +Эллиптическая кривая ******************************************************************************* */ -err_t bignStart(void* state, const bign_params* params) +err_t bakeEcStart(void* state, const bign_params* params) { // размерности size_t no, n; size_t f_keep; size_t ec_keep; // состояние - qr_o* f; /* поле */ ec_o* ec; /* кривая */ + qr_o* f; /* поле */ void* stack; /* вложенный стек */ // pre ASSERT(memIsValid(params, sizeof(bign_params))); - ASSERT(bignIsOperable(params)); - ASSERT(memIsValid(state, bignStart_keep(params->l, 0))); + ASSERT(bignParamsCheck(params) == ERR_OK); + ASSERT(memIsValid(state, bakeEcStart_keep(params->l, 0))); // определить размерности no = O_OF_B(2 * params->l); n = W_OF_B(2 * params->l); f_keep = gfpCreate_keep(no); ec_keep = ecpCreateJ_keep(n); + // разметить память + memSlice(state, + ec_keep, + f_keep, + SIZE_0, + SIZE_MAX, + &ec, &f, &stack); // создать поле - f = (qr_o*)((octet*)state + ec_keep); - stack = (octet*)f + f_keep; if (!gfpCreate(f, params->p, no, stack)) return ERR_BAD_PARAMS; ASSERT(wwBitSize(f->mod, n) == params->l * 2); ASSERT(wwGetBits(f->mod, 0, 2) == 3); // создать кривую и группу - ec = (ec_o*)state; if (!ecpCreateJ(ec, f, params->a, params->b, stack) || - !ecCreateGroup(ec, 0, params->yG, params->q, no, 1, stack)) + !ecGroupCreate(ec, 0, params->yG, params->q, no, 1, stack)) return ERR_BAD_PARAMS; ASSERT(wwBitSize(ec->order, n) == params->l * 2); ASSERT(zzIsOdd(ec->order, n)); @@ -94,7 +73,7 @@ err_t bignStart(void* state, const bign_params* params) return ERR_OK; } -size_t bignStart_keep(size_t l, bign_deep_i deep) +size_t bakeEcStart_keep(size_t l, bake_ec_deep_i deep) { // размерности size_t no = O_OF_B(2 * l); @@ -105,10 +84,59 @@ size_t bignStart_keep(size_t l, bign_deep_i deep) size_t ec_keep = ecpCreateJ_keep(n); size_t ec_deep = ecpCreateJ_deep(n, f_deep); // расчет - return f_keep + ec_keep + + return memSliceSize( + ec_keep, + f_keep, utilMax(3, ec_deep, - ecCreateGroup_deep(f_deep), - deep ? deep(n, f_deep, ec_d, ec_deep) : 0); + ecGroupCreate_deep(f_deep), + deep ? deep(n, f_deep, ec_d, ec_deep) : 0), + SIZE_MAX); } +/* +******************************************************************************* +Алгоритм bakeKDF +******************************************************************************* +*/ + +err_t bakeKDF(octet key[32], const octet secret[], size_t secret_len, + const octet iv[], size_t iv_len, size_t num) +{ + void* state; + octet* block; /* [16] */ + void* stack; + // проверить входные данные + if (!memIsValid(secret, secret_len) || + !memIsValid(iv, iv_len) || + !memIsValid(key, 32)) + return ERR_BAD_INPUT; + // создать состояние + state = blobCreate2( + (size_t)16, + utilMax(2, + beltHash_keep(), + beltKRP_keep()), + SIZE_MAX, + &block, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; + // key <- beltHash(secret || iv) + beltHashStart(stack); + beltHashStepH(secret, secret_len, stack); + beltHashStepH(iv, iv_len, stack); + beltHashStepG(key, stack); + // key <- beltKRP(Y, 1^96, num) + memSet(block, 0xFF, 12); + beltKRPStart(stack, key, 32, block); + CASSERT(B_PER_S <= 128); + memCopy(block, &num, sizeof(size_t)); +#if (OCTET_ORDER == BIG_ENDIAN) + memRev(block, sizeof(size_t)); +#endif + memSetZero(block + sizeof(size_t), 16 - sizeof(size_t)); + beltKRPStepG(key, 32, block, stack); + // завершить + blobClose(state); + return ERR_OK; +} diff --git a/src/crypto/bash/bash_f64.c b/src/crypto/bash/bash_f64.c index d30092d5..32a13b6e 100644 --- a/src/crypto/bash/bash_f64.c +++ b/src/crypto/bash/bash_f64.c @@ -4,7 +4,7 @@ \brief STB 34.101.77 (bash): bash-f \project bee2 [cryptographic library] \created 2014.07.15 -\version 2025.06.10 +\version 2025.10.03 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -173,8 +173,10 @@ static void bashF0(u64 s[24]) void bashF(octet block[192], void* stack) { - u64* s = (u64*)block; + u64* s; ASSERT(memIsDisjoint2(block, 192, stack, bashF_deep())); + ASSERT(memIsAligned(block, 8)); + s = (u64*)block; #if (OCTET_ORDER == BIG_ENDIAN) u64Rev2(s, 24); #endif diff --git a/src/crypto/bash/bash_hash.c b/src/crypto/bash/bash_hash.c index 5c675c17..141a3720 100644 --- a/src/crypto/bash/bash_hash.c +++ b/src/crypto/bash/bash_hash.c @@ -4,7 +4,7 @@ \brief STB 34.101.77 (bash): hashing algorithms \project bee2 [cryptographic library] \created 2014.07.15 -\version 2023.02.02 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -23,11 +23,11 @@ */ typedef struct { - octet s[192]; /*< состояние */ - octet s1[192]; /*< копия s */ - size_t buf_len; /*< длина буфера */ - size_t pos; /*< позиция в буфере (накоплено октетов) */ - octet stack[]; /*< [bashF_deep()] стек bashF */ + octet s[192]; /*< состояние */ + octet s1[192]; /*< копия s */ + size_t buf_len; /*< длина буфера */ + size_t pos; /*< позиция в буфере (накоплено октетов) */ + mem_align_t stack[]; /*< стек bashF */ } bash_hash_st; size_t bashHash_keep() diff --git a/src/crypto/bash/bash_prg.c b/src/crypto/bash/bash_prg.c index e6b4a093..eb5e1a9f 100644 --- a/src/crypto/bash/bash_prg.c +++ b/src/crypto/bash/bash_prg.c @@ -4,7 +4,7 @@ \brief STB 34.101.77 (bash): programmable algorithms \project bee2 [cryptographic library] \created 2018.10.30 -\version 2025.04.25 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -54,13 +54,13 @@ #define BASH_PRG_OUT 0x11 /* 000100 01 */ typedef struct { - size_t l; /*< уровень стойкости */ - size_t d; /*< емкость */ - octet s[192]; /*< состояние */ - size_t buf_len; /*< длина буфера */ - size_t pos; /*< позиция в буфере */ - octet t[192]; /*< копия состояния (для ratchet) */ - octet stack[]; /*< [bashF_deep()] стек bashF */ + size_t l; /*< уровень стойкости */ + size_t d; /*< емкость */ + octet s[192]; /*< состояние */ + size_t buf_len; /*< длина буфера */ + size_t pos; /*< позиция в буфере */ + octet t[192]; /*< копия состояния (для ratchet) */ + mem_align_t stack[]; /*< стек bashF */ } bash_prg_st; size_t bashPrg_keep() diff --git a/src/crypto/bels.c b/src/crypto/bels.c index b39709bf..107bfa7c 100644 --- a/src/crypto/bels.c +++ b/src/crypto/bels.c @@ -4,7 +4,7 @@ \brief STB 34.101.60 (bels): secret sharing algorithms \project bee2 [cryptographic library] \created 2013.05.14 -\version 2025.08.28 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -75,7 +75,7 @@ err_t belsValM(const octet m0[], size_t len) { size_t n; void* state; - word* f0; + word* f0; /* [n + 1] */ void* stack; err_t code; // проверить входные данные @@ -83,12 +83,13 @@ err_t belsValM(const octet m0[], size_t len) return ERR_BAD_INPUT; // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(n + 1) + ppIsIrred_deep(n + 1)); + state = blobCreate2( + O_OF_W(n + 1), + ppIsIrred_deep(n + 1), + SIZE_MAX, + &f0, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f0 = (word*)state; - stack = f0 + n + 1; // загрузить многочлен wwFrom(f0, m0, len); f0[n] = 1; @@ -110,9 +111,10 @@ B_PER_IMPOSSIBLE. err_t belsGenM0(octet m0[], size_t len, gen_i ang, void* ang_state) { - size_t n, reps; + size_t n; + size_t reps; void* state; - word* f0; + word* f0; /* [n + 1] */ void* stack; // проверить генератор if (ang == 0) @@ -123,12 +125,13 @@ err_t belsGenM0(octet m0[], size_t len, gen_i ang, void* ang_state) return ERR_BAD_INPUT; // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(n + 1) + ppIsIrred_deep(n + 1)); + state = blobCreate2( + O_OF_W(n + 1), + ppIsIrred_deep(n + 1), + SIZE_MAX, + &f0, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f0 = (word*)state; - stack = f0 + n + 1; // сгенерировать многочлен f0[n] = 1; for (reps = len * 8 * B_PER_IMPOSSIBLE * 3 / 4; reps--;) @@ -149,12 +152,13 @@ err_t belsGenM0(octet m0[], size_t len, gen_i ang, void* ang_state) err_t belsGenMi(octet mi[], size_t len, const octet m0[], gen_i ang, void* ang_state) { - size_t n, reps; + size_t n; + size_t reps; err_t code; void* state; - word* f0; - word* u; - word* f; + word* f0; /* [n + 1] */ + word* u; /* [n + 1] */ + word* f; /* [n + 1] (|u) */ void* stack; // проверить генератор if (ang == 0) @@ -166,14 +170,15 @@ err_t belsGenMi(octet mi[], size_t len, const octet m0[], gen_i ang, EXPECT(belsValM(m0, len) == ERR_OK); // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(2 * n + 2) + ppMinPolyMod_deep(n + 1)); + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(n + 1), + O_OF_W(n + 1) | SIZE_HI, + ppMinPolyMod_deep(n + 1), + SIZE_MAX, + &f0, &u, &f, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f0 = (word*)state; - f = f0 + n + 1; - u = f; - stack = f + n + 1; // загрузить многочлен wwFrom(f0, m0, len); f0[n] = 1; @@ -205,11 +210,12 @@ err_t belsGenMi(octet mi[], size_t len, const octet m0[], gen_i ang, err_t belsGenMid(octet mid[], size_t len, const octet m0[], const octet id[], size_t id_len) { - size_t n, reps; + size_t n; + size_t reps; void* state; - word* f0; - word* f; - word* u; + word* f0; /* [n + 1] */ + word* f; /* [n + 1] */ + word* u; /* [W_OF_O(32) + 1] */ void* stack; // проверить входные данные if ((len != 16 && len != 24 && len != 32) || @@ -219,17 +225,17 @@ err_t belsGenMid(octet mid[], size_t len, const octet m0[], const octet id[], EXPECT(belsValM(m0, len) == ERR_OK); // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(2 * n + 2) + 32 + O_PER_W + + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(n + 1), + O_OF_W(W_OF_O(32) + 1), utilMax(2, beltHash_keep(), - ppMinPolyMod_deep(n + 1))); + ppMinPolyMod_deep(n + 1)), + SIZE_MAX, + &f0, &f, &u, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f0 = (word*)state; - f = f0 + n + 1; - u = f + n + 1; - stack = u + W_OF_O(32) + 1; // загрузить многочлен wwFrom(f0, m0, len); f0[n] = 1; @@ -264,25 +270,32 @@ err_t belsGenMid(octet mid[], size_t len, const octet m0[], const octet id[], ******************************************************************************* */ +#define belsGenk_state()\ +/* in_state */ MAX2(beltCTR_keep(), beltCompr_deep()),\ +/* iv */ (size_t)32,\ +/* K */ (size_t)(16 * 4) | SIZE_HI,\ +/* key */ (size_t)32 + static size_t belsGenk_keep() { - return MAX2(beltCTR_keep(), beltCompr_deep()) + 32 + 64; + return memSliceSize(belsGenk_state(), SIZE_MAX); } static void belsGenkStart(void* state, const octet s[], size_t count, size_t threshold, size_t len) { - octet* key; - octet* iv; - u32* K; + void* in_state; /* [MAX2(beltCTR_keep(), beltCompr_deep())] */ + octet* iv; /* [32] */ + u32* K; /* [16] (|iv) */ + octet* key; /* [32] */ // pre ASSERT(memIsValid(state, belsGenk_keep())); ASSERT(len == 16 || len == 24 || len == 32); ASSERT(memIsValid(s, len)); // раскладка state - key = (octet*)state + MAX2(beltCTR_keep(), beltCompr_deep()); - iv = key + 32; - K = (u32*)iv; + memSlice(state, + belsGenk_state(), SIZE_MAX, + &in_state, &iv, &K, &key); // K <- belt-keyexpand(s) beltKeyExpand2(K, s, len); // key <- belt-compress(~K || K) @@ -315,11 +328,12 @@ err_t belsShare(octet si[], size_t count, size_t threshold, size_t len, const octet s[], const octet m0[], const octet mi[], gen_i rng, void* rng_state) { - size_t n, i; + size_t n; + size_t i; void* state; - word* f; - word* k; - word* c; + word* f; /* [n + 1] */ + word* k; /* [threshold * n - n] */ + word* c; /* [threshold * n] */ void* stack; // проверить генератор if (rng == 0) @@ -333,17 +347,17 @@ err_t belsShare(octet si[], size_t count, size_t threshold, size_t len, EXPECT(belsValM(m0, len) == ERR_OK); // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(2 * threshold * n + 1) + + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(threshold * n - n), + O_OF_W(threshold * n), utilMax(2, ppMul_deep(threshold * n - n, n), - ppMod_deep(threshold * n, n + 1))); + ppMod_deep(threshold * n, n + 1)), + SIZE_MAX, + &f, &k, &c, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f = (word*)state; - k = f + n + 1; - c = k + threshold * n - n; - stack = c + threshold * n; // сгенерировать k rng(k, threshold * len - len, rng_state); wwFrom(k, k, threshold * len - len); @@ -372,11 +386,12 @@ err_t belsShare(octet si[], size_t count, size_t threshold, size_t len, err_t belsShare2(octet si[], size_t count, size_t threshold, size_t len, const octet s[], gen_i rng, void* rng_state) { - size_t n, i; + size_t n; + size_t i; void* state; - word* f; - word* k; - word* c; + word* f; /* [n + 1] */ + word* k; /* [threshold * n - n] */ + word* c; /* [threshold * n] */ void* stack; // проверить генератор if (rng == 0) @@ -388,17 +403,17 @@ err_t belsShare2(octet si[], size_t count, size_t threshold, size_t len, return ERR_BAD_INPUT; // создать состояние n = W_OF_O(len); - state = blobCreate(O_OF_W(2 * threshold * n + 1) + + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(threshold * n - n), + O_OF_W(threshold * n), utilMax(2, ppMul_deep(threshold * n - n, n), - ppMod_deep(threshold * n, n + 1))); + ppMod_deep(threshold * n, n + 1)), + SIZE_MAX, + &f, &k, &c, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f = (word*)state; - k = f + n + 1; - c = k + threshold * n - n; - stack = c + threshold * n; // сгенерировать k rng(k, threshold * len - len, rng_state); wwFrom(k, k, threshold * len - len); @@ -459,15 +474,17 @@ err_t belsShare3(octet si[], size_t count, size_t threshold, size_t len, err_t belsRecover(octet s[], size_t count, size_t len, const octet si[], const octet m0[], const octet mi[]) { - size_t n, i, deep; + size_t n; + size_t i; + size_t deep; void* state; - word* f; - word* g; - word* d; - word* u; - word* v; - word* c; - word* t; + word* f; /* [n + 1] */ + word* g; /* [count * n + 1] */ + word* d; /* [count * n - n + 1] */ + word* u; /* [count * n - n + 1] */ + word* v; /* [n + 1] */ + word* c; /* [(2 * count - 1) * n] */ + word* t; /* [MAX2(2 * count - 2, count + 1) * n] */ void* stack; // проверить входные данные if ((len != 16 && len != 24 && len != 32) || count == 0 || @@ -488,27 +505,20 @@ err_t belsRecover(octet s[], size_t count, size_t len, const octet si[], ppMul_deep(2 * i * n, n), ppMul_deep(2 * n, i * n), ppMod_deep((2 * i + 1) * n, (i + 1) * n + 1)); - deep += O_OF_W( - n + 1 + - count * n + 1 + - (count - 1) * n + 1 + - (count - 1) * n + 1 + - n + 1 + - (2 * count - 1) * n + - MAX2((2 * count - 2) * n, (count + 1) * n)); // создать состояние - state = blobCreate(deep); + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(count * n + 1), + O_OF_W(count * n - n + 1), + O_OF_W(count * n - n + 1), + O_OF_W(n + 1), + O_OF_W((2 * count - 1) * n), + O_OF_W(MAX2(2 * count - 2, count + 1) * n), + deep, + SIZE_MAX, + &f, &g, &d, &u, &v, &c, &t, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f = (word*)state; - g = f + n + 1; - d = g + count * n + 1; - u = d + (count - 1) * n + 1; - v = u + (count - 1) * n + 1; - c = v + n + 1; - t = c + (2 * count - 1) * n; - stack = t + MAX2((2 * count - 2) * n, (count + 1) * n); // [n]c(x) <- s1(x) wwFrom(c, si, len); // [n + 1]g(x) <- x^l + m1(x) @@ -562,15 +572,18 @@ err_t belsRecover(octet s[], size_t count, size_t len, const octet si[], err_t belsRecover2(octet s[], size_t count, size_t len, const octet si[]) { - size_t n, i, j, deep; + size_t n; + size_t i; + size_t j; + size_t deep; void* state; - word* f; - word* g; - word* d; - word* u; - word* v; - word* c; - word* t; + word* f; /* [n + 1] */ + word* g; /* [count * n + 1] */ + word* d; /* [count * n - n + 1] */ + word* u; /* [count * n - n + 1] */ + word* v; /* [n + 1] */ + word* c; /* [(2 * count - 1) * n] */ + word* t; /* [MAX2(2 * count - 2, count + 1) * n] */ void* stack; // проверить входные данные if ((len != 16 && len != 24 && len != 32) || count == 0 || count > 16 || @@ -607,18 +620,19 @@ err_t belsRecover2(octet s[], size_t count, size_t len, const octet si[]) (2 * count - 1) * n + MAX2((2 * count - 2) * n, (count + 1) * n)); // создать состояние - state = blobCreate(deep); + state = blobCreate2( + O_OF_W(n + 1), + O_OF_W(count * n + 1), + O_OF_W(count * n - n + 1), + O_OF_W(count * n - n + 1), + O_OF_W(n + 1), + O_OF_W((2 * count - 1) * n), + O_OF_W(MAX2(2 * count - 2, count + 1) * n), + deep, + SIZE_MAX, + &f, &g, &d, &u, &v, &c, &t, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - f = (word*)state; - g = f + n + 1; - d = g + count * n + 1; - u = d + (count - 1) * n + 1; - v = u + (count - 1) * n + 1; - c = v + n + 1; - t = c + (2 * count - 1) * n; - stack = t + MAX2((2 * count - 2) * n, (count + 1) * n); // [n]c(x) <- s1(x) wwFrom(c, si + 1, len); // [n + 1]g(x) <- x^l + m1(x) diff --git a/src/crypto/belt/belt_bde.c b/src/crypto/belt/belt_bde.c index 95cd6417..f911ecfe 100644 --- a/src/crypto/belt/belt_bde.c +++ b/src/crypto/belt/belt_bde.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): BDE (Blockwise Disk Encryption) \project bee2 [cryptographic library] \created 2018.06.28 -\version 2020.03.24 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -28,6 +28,7 @@ typedef struct u32 key[8]; /*< форматированный ключ */ u32 s[4]; /*< переменная s */ octet block[16]; /*< вспомогательный блок */ + octet block1[16]; /*< второй вспомогательный блок */ } belt_bde_st; size_t beltBDE_keep() @@ -53,11 +54,11 @@ void beltBDEStepE(void* buf, size_t count, void* state) // цикл по блокам while(count >= 16) { - beltBlockMulC(st->s); + beltBlockMulCU32(st->s); u32To(st->block, 16, st->s); - beltBlockXor2(buf, st->block); - beltBlockEncr(buf, st->key); - beltBlockXor2(buf, st->block); + beltBlockXor(st->block1, buf, st->block); + beltBlockEncr(st->block1, st->key); + beltBlockXor(buf, st->block1, st->block); buf = (octet*)buf + 16; count -= 16; } @@ -71,11 +72,11 @@ void beltBDEStepD(void* buf, size_t count, void* state) // цикл по блокам while(count >= 16) { - beltBlockMulC(st->s); + beltBlockMulCU32(st->s); u32To(st->block, 16, st->s); - beltBlockXor2(buf, st->block); - beltBlockDecr(buf, st->key); - beltBlockXor2(buf, st->block); + beltBlockXor(st->block1, buf, st->block); + beltBlockDecr(st->block1, st->key); + beltBlockXor(buf, st->block1, st->block); buf = (octet*)buf + 16; count -= 16; } diff --git a/src/crypto/belt/belt_block.c b/src/crypto/belt/belt_block.c index 1bf537f4..cd2b4459 100644 --- a/src/crypto/belt/belt_block.c +++ b/src/crypto/belt/belt_block.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): block encryption \project bee2 [cryptographic library] \created 2012.12.18 -\version 2025.04.25 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -80,9 +80,8 @@ void beltKeyExpand(octet key_[32], const octet key[], size_t len) memCopy(key_ + 16, key_, 16); else if (len == 24) { - u32* w = (u32*)key_; - w[6] = w[0] ^ w[1] ^ w[2]; - w[7] = w[3] ^ w[4] ^ w[5]; + memXor(key_ + 24, key + 0, key + 8, 8); + memXor2(key_ + 24, key + 16, 8); } } @@ -294,8 +293,10 @@ a <-> b, c <-> d, a <-> d. */ void beltBlockEncr(octet block[16], const u32 key[8]) { - u32* t = (u32*)block; + u32* t; + ASSERT(memIsAligned(block, 4)); ASSERT(memIsDisjoint2(block, 16, key, 32)); + t = (u32*)block; #if (OCTET_ORDER == BIG_ENDIAN) t[0] = u32Rev(t[0]); t[1] = u32Rev(t[1]); @@ -328,8 +329,10 @@ void beltBlockEncr3(u32* a, u32* b, u32* c, u32* d, const u32 key[8]) */ void beltBlockDecr(octet block[16], const u32 key[8]) { - u32* t = (u32*)block; + u32* t; + ASSERT(memIsAligned(block, 4)); ASSERT(memIsDisjoint2(block, 16, key, 32)); + t = (u32*)block; #if (OCTET_ORDER == BIG_ENDIAN) t[0] = u32Rev(t[0]); t[1] = u32Rev(t[1]); diff --git a/src/crypto/belt/belt_cbc.c b/src/crypto/belt/belt_cbc.c index d8179327..f56591ec 100644 --- a/src/crypto/belt/belt_cbc.c +++ b/src/crypto/belt/belt_cbc.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): CBC encryption \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.24 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -20,13 +20,58 @@ /* ******************************************************************************* Шифрование в режиме CBС + +\remark Оптимизированный код при условии выравнивания buf: +\code +void beltCBCStepE(void* buf, size_t count, void* state) +{ + ... + while(count >= 16) + { + beltBlockXor2(st->block, buf); + beltBlockEncr(st->block, st->key); + beltBlockCopy(buf, st->block); + buf = (octet*)buf + 16; + count -= 16; + } + if (count) + { + memSwap((octet*)buf - 16, buf, count); + memXor2((octet*)buf - 16, st->block, count); + beltBlockEncr((octet*)buf - 16, st->key); + } +} + +void beltCBCStepD(void* buf, size_t count, void* state) +{ + ... + while(count >= 32 || count == 16) + { + beltBlockCopy(st->block1, buf); + beltBlockDecr(buf, st->key); + beltBlockXor2(buf, st->block); + beltBlockCopy(st->block, st->block1); + buf = (octet*)buf + 16; + count -= 16; + } + if (count) + { + ASSERT(16 < count && count < 32); + beltBlockDecr(buf, st->key); + memSwap(buf, (octet*)buf + 16, count - 16); + memXor2((octet*)buf + 16, buf, count - 16); + beltBlockDecr(buf, st->key); + beltBlockXor2(buf, st->block); + } +} +\endcode ******************************************************************************* */ typedef struct { u32 key[8]; /*< форматированный ключ */ octet block[16]; /*< вспомогательный блок */ - octet block2[16]; /*< еще один вспомогательный блок */ + octet block1[16]; /*< второй вспомогательный блок */ } belt_cbc_st; size_t beltCBC_keep() @@ -60,9 +105,11 @@ void beltCBCStepE(void* buf, size_t count, void* state) // неполный блок? кража блока if (count) { - memSwap((octet*)buf - 16, buf, count); - memXor2((octet*)buf - 16, st->block, count); - beltBlockEncr((octet*)buf - 16, st->key); + memXor(st->block1, buf, st->block, count); + memCopy(st->block1 + count, (octet*)buf - 16 + count, 16 - count); + beltBlockEncr(st->block1, st->key); + memCopy(buf, (octet*)buf - 16, count); + beltBlockCopy((octet*)buf - 16, st->block1); } } @@ -74,10 +121,11 @@ void beltCBCStepD(void* buf, size_t count, void* state) // цикл по полным блокам while(count >= 32 || count == 16) { - beltBlockCopy(st->block2, buf); - beltBlockDecr(buf, st->key); - beltBlockXor2(buf, st->block); - beltBlockCopy(st->block, st->block2); + beltBlockCopy(st->block1, buf); + beltBlockDecr(st->block1, st->key); + beltBlockXor2(st->block1, st->block); + beltBlockCopy(st->block, buf); + beltBlockCopy(buf, st->block1); buf = (octet*)buf + 16; count -= 16; } @@ -85,11 +133,12 @@ void beltCBCStepD(void* buf, size_t count, void* state) if (count) { ASSERT(16 < count && count < 32); - beltBlockDecr(buf, st->key); - memSwap(buf, (octet*)buf + 16, count - 16); - memXor2((octet*)buf + 16, buf, count - 16); - beltBlockDecr(buf, st->key); - beltBlockXor2(buf, st->block); + beltBlockCopy(st->block1, buf); + beltBlockDecr(st->block1, st->key); + memSwap(st->block1, (octet*)buf + 16, count - 16); + memXor2((octet*)buf + 16, st->block1, count - 16); + beltBlockDecr(st->block1, st->key); + beltBlockXor(buf, st->block1, st->block); } } diff --git a/src/crypto/belt/belt_che.c b/src/crypto/belt/belt_che.c index fabda105..747776ca 100644 --- a/src/crypto/belt/belt_che.c +++ b/src/crypto/belt/belt_che.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): CHE (Ctr-Hash-Encrypt) authenticated encryption \project bee2 [cryptographic library] \created 2020.03.20 -\version 2025.08.28 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -36,7 +36,7 @@ typedef struct octet block1[16]; /*< блок гаммы */ size_t filled; /*< накоплено октетов в block */ size_t reserved; /*< резерв октетов гаммы */ - octet stack[]; /*< стек умножения */ + mem_align_t stack[]; /*< стек умножения */ } belt_che_st; size_t beltCHE_keep() @@ -86,8 +86,9 @@ void beltCHEStepE(void* buf, size_t count, void* state) // цикл по полным блокам while (count >= 16) { - beltBlockMulC(st->s), st->s[0] ^= 0x00000001; + beltBlockMulCU32(st->s), st->s[0] ^= 0x00000001; beltBlockCopy(st->block1, st->s); + ASSERT(memIsAligned(st->block1, 4)); beltBlockEncr2((u32*)st->block1, st->key); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block1); @@ -99,8 +100,9 @@ void beltCHEStepE(void* buf, size_t count, void* state) // неполный блок? if (count) { - beltBlockMulC(st->s), st->s[0] ^= 0x00000001; + beltBlockMulCU32(st->s), st->s[0] ^= 0x00000001; beltBlockCopy(st->block1, st->s); + ASSERT(memIsAligned(st->block1, 4)); beltBlockEncr2((u32*)st->block1, st->key); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block1); diff --git a/src/crypto/belt/belt_compr.c b/src/crypto/belt/belt_compr.c index 4a60d66f..8d7b449d 100644 --- a/src/crypto/belt/belt_compr.c +++ b/src/crypto/belt/belt_compr.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): compression \project bee2 [cryptographic library] \created 2012.12.18 -\version 2025.04.25 +\version 2025.09.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -26,8 +26,10 @@ h и X разбиваются на половинки: void beltCompr(u32 h[8], const u32 X[8], void* stack) { + u32* buf; // [12]buf = [4]buf0 || [4]buf1 || [4]buf2 - u32* buf = (u32*)stack; + ASSERT(memIsAligned(stack, 4)); + buf = (u32*)stack; // буферы не пересекаются? ASSERT(memIsDisjoint3(h, 32, X, 32, buf, 48)); // buf0, buf1 <- h0 + h1 @@ -54,8 +56,10 @@ void beltCompr(u32 h[8], const u32 X[8], void* stack) void beltCompr2(u32 s[4], u32 h[8], const u32 X[8], void* stack) { + u32* buf; // [12]buf = [4]buf0 || [4]buf1 || [4]buf2 - u32* buf = (u32*)stack; + ASSERT(memIsAligned(stack, 4)); + buf = (u32*)stack; // буферы не пересекаются? ASSERT(memIsDisjoint4(s, 16, h, 32, X, 32, buf, 48)); // buf0, buf1 <- h0 + h1 diff --git a/src/crypto/belt/belt_ctr.c b/src/crypto/belt/belt_ctr.c index 9a8388d1..f8940a17 100644 --- a/src/crypto/belt/belt_ctr.c +++ b/src/crypto/belt/belt_ctr.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): CTR encryption \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.24 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -18,6 +18,23 @@ #include "bee2/crypto/belt.h" #include "belt_lcl.h" +/* +******************************************************************************* +Инкремент +******************************************************************************* +*/ + +static void beltBlockIncU32(u32 block[4]) +{ + register u32 carry = 1; + block[0] += carry, carry = wordLess(block[0], carry); + block[1] += carry, carry = wordLess(block[1], carry); + block[2] += carry, carry = wordLess(block[2], carry); + block[3] += carry; + CLEAN(carry); +} + + /* ******************************************************************************* Шифрование в режиме CTR @@ -69,6 +86,7 @@ void beltCTRStepE(void* buf, size_t count, void* state) { beltBlockIncU32(st->ctr); beltBlockCopy(st->block, st->ctr); + ASSERT(memIsAligned(st->block, 4)); beltBlockEncr2((u32*)st->block, st->key); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block); @@ -82,6 +100,7 @@ void beltCTRStepE(void* buf, size_t count, void* state) { beltBlockIncU32(st->ctr); beltBlockCopy(st->block, st->ctr); + ASSERT(memIsAligned(st->block, 4)); beltBlockEncr2((u32*)st->block, st->key); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block); diff --git a/src/crypto/belt/belt_dwp.c b/src/crypto/belt/belt_dwp.c index 24267fc9..6e3a4230 100644 --- a/src/crypto/belt/belt_dwp.c +++ b/src/crypto/belt/belt_dwp.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): DWP (datawrap = data encryption + authentication) \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.24 +\version 2025.10.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -33,7 +33,7 @@ typedef struct word len[W_OF_B(128)]; /*< обработано открытых || критических данных */ octet block[16]; /*< блок данных */ size_t filled; /*< накоплено октетов в блоке */ - octet stack[]; /*< стек умножения */ + mem_align_t stack[]; /*< стек умножения */ } belt_dwp_st; size_t beltDWP_keep() @@ -50,6 +50,7 @@ void beltDWPStart(void* state, const octet key[], size_t len, beltCTRStart(st->ctr, key, len, iv); // установить r, s beltBlockCopy(st->r, st->ctr->ctr); + ASSERT(memIsAligned(st->r, 4)); beltBlockEncr2((u32*)st->r, st->ctr->key); #if (OCTET_ORDER == BIG_ENDIAN && B_PER_W != 32) beltBlockRevU32(st->r); diff --git a/src/crypto/belt/belt_ecb.c b/src/crypto/belt/belt_ecb.c index 9c676626..95999d5b 100644 --- a/src/crypto/belt/belt_ecb.c +++ b/src/crypto/belt/belt_ecb.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): ECB encryption \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.24 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -15,15 +15,36 @@ #include "bee2/core/mem.h" #include "bee2/core/util.h" #include "bee2/crypto/belt.h" +#include "belt_lcl.h" /* ******************************************************************************* Шифрование в режиме ECB + +\remark Чтобы соблюсти предусловия выравнивания в функциях beltBlockEncr() и +beltBlockDecr(), перед обращениями к ним блок данных переписывается в поле +block структуры belt_ecb_st. Код будет компактнее и эффективнее, если +потребовать, чтобы обрабатываемый буфер buf был выровнен на границу u32. +Например вот так будет выглядеть основная часть beltECBStepE(): +\code + while(count >= 16) + { + beltBlockDecr(buf, st->key); + buf = (octet*)buf + 16; + count -= 16; + } + if (count) + { + memSwap((octet*)buf - 16, buf, count); + beltBlockDecr((octet*)buf - 16, st->key); + } +\endcode ******************************************************************************* */ typedef struct { - u32 key[8]; /*< форматированный ключ */ + u32 key[8]; /*< форматированный ключ */ + octet block[16]; /*< вспомогательный блок */ } belt_ecb_st; size_t beltECB_keep() @@ -46,15 +67,20 @@ void beltECBStepE(void* buf, size_t count, void* state) // цикл по полным блокам while(count >= 16) { - beltBlockEncr(buf, st->key); + beltBlockCopy(st->block, buf); + beltBlockEncr(st->block, st->key); + beltBlockCopy(buf, st->block); buf = (octet*)buf + 16; count -= 16; } // неполный блок? кража блока if (count) { - memSwap((octet*)buf - 16, buf, count); - beltBlockEncr((octet*)buf - 16, st->key); + memCopy(st->block, buf, count); + memCopy(st->block + count, (octet*)buf - 16 + count, 16 - count); + beltBlockEncr(st->block, st->key); + memCopy(buf, (octet*)buf - 16, count); + beltBlockCopy((octet*)buf - 16, st->block); } } @@ -66,15 +92,20 @@ void beltECBStepD(void* buf, size_t count, void* state) // цикл по полным блокам while(count >= 16) { - beltBlockDecr(buf, st->key); + beltBlockCopy(st->block, buf); + beltBlockDecr(st->block, st->key); + beltBlockCopy(buf, st->block); buf = (octet*)buf + 16; count -= 16; } // неполный блок? кража блока if (count) { - memSwap((octet*)buf - 16, buf, count); - beltBlockDecr((octet*)buf - 16, st->key); + memCopy(st->block, buf, count); + memCopy(st->block + count, (octet*)buf - 16 + count, 16 - count); + beltBlockDecr(st->block, st->key); + memCopy(buf, (octet*)buf - 16, count); + beltBlockCopy((octet*)buf - 16, st->block); } } diff --git a/src/crypto/belt/belt_fmt.c b/src/crypto/belt/belt_fmt.c index 25f877d0..f71359a0 100644 --- a/src/crypto/belt/belt_fmt.c +++ b/src/crypto/belt/belt_fmt.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): FMT (format preserving encryption) \project bee2 [cryptographic library] \created 2017.09.28 -\version 2021.01.21 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -73,16 +73,16 @@ static size_t beltFMTCalcB(u32 mod, size_t count) { - const size_t m = W_OF_B(128); - word num[W_OF_B(128)]; - word den[W_OF_B(128)]; + enum {m = W_OF_B(128)}; + word num[m]; + word den[m]; size_t k; - word stack[W_OF_B(128) * 5]; - word* t0 = stack; - word* t1 = t0 + m; - word* t2 = t1 + m; - word* t3 = t2 + m; - word* t4 = t3 + m; + mem_align_t stack[O_OF_W(m) * 5 / sizeof(mem_align_t) + 1]; + word* t0 = (word*)stack; + word* t1 = t0 + m; + word* t2 = t1 + m; + word* t3 = t2 + m; + word* t4 = t3 + m; // pre ASSERT(2 <= mod && mod <= 65536); ASSERT(1 <= count && count <= 300); @@ -156,7 +156,10 @@ belt-32block static void belt32BlockEncr(octet block[24], const u32 key[8]) { - u32* t = (u32*)block; + u32* t; + // подготовить block + ASSERT(memIsAligned(block, 4)); + t = (u32*)block; u32From(t, block, 24); // round #1 beltBlockEncr3(t + 2, t + 3, t + 4, t + 5, key); @@ -177,7 +180,7 @@ static void belt32BlockEncr(octet block[24], const u32 key[8]) ******************************************************************************* */ -static void beltStr2Bin(octet bin[], size_t b, u32 mod, +static void beltStr2Bin(void* bin, size_t b, u32 mod, const u16 str[], size_t count) { word* a; @@ -195,6 +198,7 @@ static void beltStr2Bin(octet bin[], size_t b, u32 mod, ASSERT(count >= 1); --count; EXPECT(str[count] < mod); + ASSERT(memIsAligned(bin, O_PER_W)); a = (word*)bin; m = W_OF_O(8 * b); a[0] = (word)str[count]; @@ -208,7 +212,7 @@ static void beltStr2Bin(octet bin[], size_t b, u32 mod, } static void beltBin2StrAdd(u32 mod, u16 str[], size_t count, - octet bin[], size_t b) + void* bin, size_t b) { register u32 t; word* a; @@ -223,6 +227,7 @@ static void beltBin2StrAdd(u32 mod, u16 str[], size_t count, return; } // настроить память + ASSERT(memIsAligned(bin, O_PER_W)); m = W_OF_O(8 * b); a = (word*)bin; wwFrom(a, bin, 8 * b); @@ -239,7 +244,7 @@ static void beltBin2StrAdd(u32 mod, u16 str[], size_t count, } static void beltBin2StrSub(word mod, u16 str[], size_t count, - octet bin[], size_t b) + void* bin, size_t b) { register u32 t; word* a; @@ -254,6 +259,7 @@ static void beltBin2StrSub(word mod, u16 str[], size_t count, return; } // настроить память + ASSERT(memIsAligned(bin, O_PER_W)); m = W_OF_O(8 * b); a = (word*)bin; wwFrom(a, bin, 8 * b); @@ -291,7 +297,7 @@ typedef struct size_t b1; /*< число блоков для обработки левой половинки */ size_t b2; /*< число блоков для обработки правой половинки */ octet iv[4 + 16 + 4]; /*< формат || синхропосылка || формат */ - octet buf[]; /*< вспомогательный буфер */ + mem_align_t buf[]; /*< вспомогательный буфер */ } belt_fmt_st; size_t beltFMT_keep(u32 mod, size_t count) @@ -304,17 +310,19 @@ size_t beltFMT_keep(u32 mod, size_t count) void beltFMTStart(void* state, u32 mod, size_t count, const octet key[], size_t len) { - belt_fmt_st* st = (belt_fmt_st*)state; + belt_fmt_st* st; ASSERT(2 <= mod && mod <= 65536); ASSERT(2 <= count && count <= 600); ASSERT(memIsValid(state, beltFMT_keep(mod, count))); // инициализировать состояние + st = (belt_fmt_st*)state; beltWBLStart(st->wbl, key, len); st->mod = mod; st->n1 = (count + 1) / 2; st->n2 = count / 2; st->b1 = beltFMTCalcB(mod, st->n1); st->b2 = beltFMTCalcB(mod, st->n2); + ASSERT(memIsAligned(st->iv, 2)); #if (OCTET_ORDER == LITTLE_ENDIAN) ((u16*)st->iv)[0] = (u16)mod; ((u16*)st->iv)[1] = (u16)count; @@ -329,6 +337,7 @@ void beltFMTStepE(u16 buf[], const octet iv[16], void* state) { belt_fmt_st* st = (belt_fmt_st*)state; size_t i; + // pre ASSERT(memIsValid(state, sizeof(belt_fmt_st))); ASSERT(memIsValid(state, beltFMT_keep(st->mod, st->n1 + st->n2))); ASSERT(memIsNullOrValid(iv, 16)); @@ -341,28 +350,29 @@ void beltFMTStepE(u16 buf[], const octet iv[16], void* state) // такты for (i = 0; i < 3; ++i) { + octet* bin = (octet*)st->buf; // первая половинка - beltStr2Bin(st->buf, st->b2, st->mod, buf + st->n1, st->n2); - memCopy(st->buf + st->b2 * 8, beltH() + 8 * i, 4); - memCopy(st->buf + st->b2 * 8 + 4, st->iv + 8 * i, 4); + beltStr2Bin(bin, st->b2, st->mod, buf + st->n1, st->n2); + memCopy(bin + st->b2 * 8, beltH() + 8 * i, 4); + memCopy(bin + st->b2 * 8 + 4, st->iv + 8 * i, 4); if (st->b2 == 1) - beltBlockEncr(st->buf, st->wbl->key); + beltBlockEncr(bin, st->wbl->key); else if (st->b2 == 2) - belt32BlockEncr(st->buf, st->wbl->key); + belt32BlockEncr(bin, st->wbl->key); else - beltWBLStepE(st->buf, 8 * st->b2 + 8, st->wbl); - beltBin2StrAdd(st->mod, buf, st->n1, st->buf, st->b2 + 1); + beltWBLStepE(bin, 8 * st->b2 + 8, st->wbl); + beltBin2StrAdd(st->mod, buf, st->n1, bin, st->b2 + 1); // вторая половинка - beltStr2Bin(st->buf, st->b1, st->mod, buf, st->n1); - memCopy(st->buf + st->b1 * 8, beltH() + 8 * i + 4, 4); - memCopy(st->buf + st->b1 * 8 + 4, st->iv + 8 * i + 4, 4); + beltStr2Bin(bin, st->b1, st->mod, buf, st->n1); + memCopy(bin + st->b1 * 8, beltH() + 8 * i + 4, 4); + memCopy(bin + st->b1 * 8 + 4, st->iv + 8 * i + 4, 4); if (st->b1 == 1) - beltBlockEncr(st->buf, st->wbl->key); + beltBlockEncr(bin, st->wbl->key); else if (st->b1 == 2) - belt32BlockEncr(st->buf, st->wbl->key); + belt32BlockEncr(bin, st->wbl->key); else - beltWBLStepE(st->buf, 8 * st->b1 + 8, st->wbl); - beltBin2StrAdd(st->mod, buf + st->n1, st->n2, st->buf, st->b1 + 1); + beltWBLStepE(bin, 8 * st->b1 + 8, st->wbl); + beltBin2StrAdd(st->mod, buf + st->n1, st->n2, bin, st->b1 + 1); } } @@ -370,6 +380,7 @@ void beltFMTStepD(u16 buf[], const octet iv[16], void* state) { belt_fmt_st* st = (belt_fmt_st*)state; size_t i; + // pre ASSERT(memIsValid(state, sizeof(belt_fmt_st))); ASSERT(memIsValid(state, beltFMT_keep(st->mod, st->n1 + st->n2))); ASSERT(memIsNullOrValid(iv, 16)); @@ -382,28 +393,29 @@ void beltFMTStepD(u16 buf[], const octet iv[16], void* state) // такты for (i = 3; i--;) { + octet* bin = (octet*)st->buf; // вторая половинка - beltStr2Bin(st->buf, st->b1, st->mod, buf, st->n1); - memCopy(st->buf + st->b1 * 8, beltH() + 8 * i + 4, 4); - memCopy(st->buf + st->b1 * 8 + 4, st->iv + 8 * i + 4, 4); + beltStr2Bin(bin, st->b1, st->mod, buf, st->n1); + memCopy(bin + st->b1 * 8, beltH() + 8 * i + 4, 4); + memCopy(bin + st->b1 * 8 + 4, st->iv + 8 * i + 4, 4); if (st->b1 == 1) - beltBlockEncr(st->buf, st->wbl->key); + beltBlockEncr(bin, st->wbl->key); else if (st->b1 == 2) - belt32BlockEncr(st->buf, st->wbl->key); + belt32BlockEncr(bin, st->wbl->key); else - beltWBLStepE(st->buf, 8 * st->b1 + 8, st->wbl); - beltBin2StrSub(st->mod, buf + st->n1, st->n2, st->buf, st->b1 + 1); + beltWBLStepE(bin, 8 * st->b1 + 8, st->wbl); + beltBin2StrSub(st->mod, buf + st->n1, st->n2, bin, st->b1 + 1); // первая половинка - beltStr2Bin(st->buf, st->b2, st->mod, buf + st->n1, st->n2); - memCopy(st->buf + st->b2 * 8, beltH() + 8 * i, 4); - memCopy(st->buf + st->b2 * 8 + 4, st->iv + 8 * i, 4); + beltStr2Bin(bin, st->b2, st->mod, buf + st->n1, st->n2); + memCopy(bin + st->b2 * 8, beltH() + 8 * i, 4); + memCopy(bin + st->b2 * 8 + 4, st->iv + 8 * i, 4); if (st->b2 == 1) - beltBlockEncr(st->buf, st->wbl->key); + beltBlockEncr(bin, st->wbl->key); else if (st->b2 == 2) - belt32BlockEncr(st->buf, st->wbl->key); + belt32BlockEncr(bin, st->wbl->key); else - beltWBLStepE(st->buf, 8 * st->b2 + 8, st->wbl); - beltBin2StrSub(st->mod, buf, st->n1, st->buf, st->b2 + 1); + beltWBLStepE(bin, 8 * st->b2 + 8, st->wbl); + beltBin2StrSub(st->mod, buf, st->n1, bin, st->b2 + 1); } } diff --git a/src/crypto/belt/belt_hash.c b/src/crypto/belt/belt_hash.c index 870879a7..e7337534 100644 --- a/src/crypto/belt/belt_hash.c +++ b/src/crypto/belt/belt_hash.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): hashing \project bee2 [cryptographic library] \created 2012.12.18 -\version 2022.07.18 +\version 2025.10.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -32,7 +32,7 @@ typedef struct { u32 h1[8]; /*< копия переменной h */ octet block[32]; /*< блок данных */ size_t filled; /*< накоплено октетов в блоке */ - octet stack[]; /*< [beltCompr_deep()] стек beltCompr */ + mem_align_t stack[]; /*< стек beltCompr */ } belt_hash_st; size_t beltHash_keep() @@ -75,6 +75,7 @@ void beltHashStepH(const void* buf, size_t count, void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls + 4, st->h, (u32*)st->block, st->stack); st->filled = 0; } @@ -87,6 +88,7 @@ void beltHashStepH(const void* buf, size_t count, void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls + 4, st->h, (u32*)st->block, st->stack); buf = (const octet*)buf + 32; count -= 32; @@ -113,6 +115,7 @@ static void beltHashStepG_internal(void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls + 4, st->h1, (u32*)st->block, st->stack); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block + 16); diff --git a/src/crypto/belt/belt_hmac.c b/src/crypto/belt/belt_hmac.c index 67c25b28..65ca530f 100644 --- a/src/crypto/belt/belt_hmac.c +++ b/src/crypto/belt/belt_hmac.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): HMAC message authentication \project bee2 [cryptographic library] \created 2012.12.18 -\version 2022.07.18 +\version 2025.10.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -25,16 +25,16 @@ */ typedef struct { - u32 ls_in[8]; /*< блок [4]len || [4]s внутреннего хэширования */ - u32 h_in[8]; /*< переменная h внутреннего хэширования */ - u32 h1_in[8]; /*< копия переменной h внутреннего хэширования */ - u32 ls_out[8]; /*< блок [4]len || [4]s внешнего хэширования */ - u32 h_out[8]; /*< переменная h внешнего хэширования */ - u32 h1_out[8]; /*< копия переменной h внешнего хэширования */ - u32 s1[4]; /*< копия переменной s */ - octet block[32]; /*< блок данных */ - size_t filled; /*< накоплено октетов в блоке */ - octet stack[]; /*< [beltCompr_deep()] стек beltCompr */ + u32 ls_in[8]; /*< блок [4]len || [4]s внутреннего хэширования */ + u32 h_in[8]; /*< переменная h внутреннего хэширования */ + u32 h1_in[8]; /*< копия переменной h внутреннего хэширования */ + u32 ls_out[8]; /*< блок [4]len || [4]s внешнего хэширования */ + u32 h_out[8]; /*< переменная h внешнего хэширования */ + u32 h1_out[8]; /*< копия переменной h внешнего хэширования */ + u32 s1[4]; /*< копия переменной s */ + octet block[32]; /*< блок данных */ + size_t filled; /*< накоплено октетов в блоке */ + mem_align_t stack[]; /*< стек beltCompr */ } belt_hmac_st; size_t beltHMAC_keep() @@ -71,6 +71,7 @@ void beltHMACStart(void* state, const octet key[], size_t len) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack); key += 32; len -= 32; @@ -83,6 +84,7 @@ void beltHMACStart(void* state, const octet key[], size_t len) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack); } beltCompr(st->h_in, st->ls_in, st->stack); @@ -97,6 +99,7 @@ void beltHMACStart(void* state, const octet key[], size_t len) beltBlockAddBitSizeU32(st->ls_in, 32); beltBlockSetZero(st->ls_in + 4); u32From(st->h_in, beltH(), 32); + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack); st->filled = 0; // сформировать key ^ opad [0x36 ^ 0x5C == 0x6A] @@ -107,6 +110,7 @@ void beltHMACStart(void* state, const octet key[], size_t len) beltBlockAddBitSizeU32(st->ls_out, 32 * 2); beltBlockSetZero(st->ls_out + 4); u32From(st->h_out, beltH(), 32); + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_out + 4, st->h_out, (u32*)st->block, st->stack); } @@ -132,6 +136,7 @@ void beltHMACStepA(const void* buf, size_t count, void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack); st->filled = 0; } @@ -144,6 +149,7 @@ void beltHMACStepA(const void* buf, size_t count, void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack); buf = (const octet*)buf + 32; count -= 32; @@ -170,6 +176,7 @@ static void beltHMACStepG_internal(void* state) beltBlockRevU32(st->block); beltBlockRevU32(st->block + 16); #endif + ASSERT(memIsAligned(st->block, 4)); beltCompr2(st->ls_in + 4, st->h1_in, (u32*)st->block, st->stack); #if (OCTET_ORDER == BIG_ENDIAN) beltBlockRevU32(st->block + 16); diff --git a/src/crypto/belt/belt_krp.c b/src/crypto/belt/belt_krp.c index eb06b2c9..c649cc4e 100644 --- a/src/crypto/belt/belt_krp.c +++ b/src/crypto/belt/belt_krp.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): KRP (keyrep = key diversification + meshing) \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.24 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -25,11 +25,11 @@ */ typedef struct { - u32 key[8]; /*< форматированный первоначальный ключ */ - size_t len; /*< длина первоначального ключа */ - u32 block[8]; /*< блок r || level || header */ - u32 key_new[8]; /*< форматированный преобразованный ключ */ - octet stack[]; /*< стек beltCompr */ + u32 key[8]; /*< форматированный первоначальный ключ */ + size_t len; /*< длина первоначального ключа */ + u32 block[8]; /*< блок r || level || header */ + u32 key_new[8]; /*< форматированный преобразованный ключ */ + mem_align_t stack[]; /*< стек beltCompr */ } belt_krp_st; size_t beltKRP_keep() diff --git a/src/crypto/belt/belt_kwp.c b/src/crypto/belt/belt_kwp.c index f456ab7d..78b2a5b3 100644 --- a/src/crypto/belt/belt_kwp.c +++ b/src/crypto/belt/belt_kwp.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): KWP (keywrap = key encryption + authentication) \project bee2 [cryptographic library] \created 2012.12.18 -\version 2019.06.26 +\version 2025.09.15 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -55,7 +55,8 @@ err_t beltKWPUnwrap(octet dest[], const octet src[], size_t count, const octet header[16], const octet key[], size_t len) { void* state; - octet* header2; + octet* header2; /* [16] */ + void* kwp_state; /* beltKWP_keep() */ // проверить входные данные if (count < 32 || len != 16 && len != 24 && len != 32 || @@ -65,15 +66,18 @@ err_t beltKWPUnwrap(octet dest[], const octet src[], size_t count, !memIsValid(dest, count - 16)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(beltKWP_keep() + 16); + state = blobCreate2( + (size_t)16, + beltKWP_keep(), + SIZE_MAX, + &header2, &kwp_state); if (state == 0) return ERR_OUTOFMEMORY; - header2 = (octet*)state + beltKWP_keep(); // снять защиту - beltKWPStart(state, key, len); + beltKWPStart(kwp_state, key, len); memCopy(header2, src + count - 16, 16); memMove(dest, src, count - 16); - beltKWPStepD2(dest, header2, count, state); + beltKWPStepD2(dest, header2, count, kwp_state); if (header && !memEq(header, header2, 16) || header == 0 && !memIsZero(header2, 16)) { diff --git a/src/crypto/belt/belt_lcl.c b/src/crypto/belt/belt_lcl.c index 72e276a9..c3c902b4 100644 --- a/src/crypto/belt/belt_lcl.c +++ b/src/crypto/belt/belt_lcl.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): local functions \project bee2 [cryptographic library] \created 2012.12.18 -\version 2025.06.10 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -17,13 +17,13 @@ /* ******************************************************************************* -Арифметика чисел +Сложения + block <- block + 8 * count ******************************************************************************* */ void beltBlockAddBitSizeU32(u32 block[4], size_t count) { - // block <- block + 8 * count register u32 carry = (u32)count << 3; #if (B_PER_S < 32) carry = (block[0] += carry) < carry; @@ -52,30 +52,34 @@ void beltBlockAddBitSizeU32(u32 block[4], size_t count) void beltHalfBlockAddBitSizeW(word block[W_OF_B(64)], size_t count) { - // block <- block + 8 * count register word carry = (word)count << 3; #if (B_PER_W == 16) - register size_t t = count >> 13; - carry = (block[0] += carry) < carry; - if ((block[1] += carry) < carry) - block[1] = (word)t; - else - carry = (block[1] += (word)t) < (word)t; - t >>= 8, t >>= 8; - if ((block[2] += carry) < carry) - block[2] = (word)t; - else - carry = (block[2] += (word)t) < (word)t; - t >>= 8, t >>= 8; - block[3] += carry; - block[3] += (word)t; + { + register size_t t = count >> 13; + carry = (block[0] += carry) < carry; + if ((block[1] += carry) < carry) + block[1] = (word)t; + else + carry = (block[1] += (word)t) < (word)t; + t >>= 8, t >>= 8; + if ((block[2] += carry) < carry) + block[2] = (word)t; + else + carry = (block[2] += (word)t) < (word)t; + t >>= 8, t >>= 8; + block[3] += carry; + block[3] += (word)t; + CLEAN(t); + } #elif (B_PER_W == 32) - register size_t t = count; - carry = (block[0] += carry) < carry; - t >>= 15, t >>= 14; - block[1] += carry; - block[1] += (u32)t; - CLEAN(t); + { + register size_t t = count; + carry = (block[0] += carry) < carry; + t >>= 15, t >>= 14; + block[1] += carry; + block[1] += (u32)t; + CLEAN(t); + } #elif (B_PER_W == 64) block[0] += carry; #else @@ -86,15 +90,40 @@ void beltHalfBlockAddBitSizeW(word block[W_OF_B(64)], size_t count) /* ******************************************************************************* -Арифметика многочленов +Умножение на многочлен C(x) = x mod (x^128 + x^7 + x^2 + x + 1) + +\remark t = (старший бит block ненулевой) ? x^7 + x^2 + x + 1 : 0 [регулярно]. ******************************************************************************* */ +void beltBlockMulCU32(u32 block[4]) +{ + register u32 t; + t = ~((block[3] >> 31) - U32_1) & 0x00000087; + block[3] <<= 1, block[3] ^= (block[2] >> 31); + block[2] <<= 1, block[2] ^= (block[1] >> 31); + block[1] <<= 1, block[1] ^= (block[0] >> 31); + block[0] <<= 1, block[0] ^= t; + CLEAN(t); +} + +/* +******************************************************************************* +Умножение c(x) <- a(x) * b(x) mod (x^128 + x^7 + x^2 + x + 1) +******************************************************************************* +*/ + +#define beltPolyMul_local(n)\ +/* prod */ O_OF_W(2 * n) + void beltPolyMul(word c[], const word a[], const word b[], void* stack) { const size_t n = W_OF_B(128); - word* prod = (word*)stack; - stack = prod + 2 * n; + word* prod; /* [2 * n] */ + // разметить стек + memSlice(stack, + beltPolyMul_local(n), SIZE_0, SIZE_MAX, + &prod, &stack); // умножить ppMul(prod, a, n, b, n, stack); // привести по модулю @@ -105,23 +134,8 @@ void beltPolyMul(word c[], const word a[], const word b[], void* stack) size_t beltPolyMul_deep() { const size_t n = W_OF_B(128); - return O_OF_W(2 * n) + ppMul_deep(n, n); -} - -/* -******************************************************************************* -Умножение на многочлен C(x) = x mod (x^128 + x^7 + x^2 + x + 1) - -\remark t = (старший бит block ненулевой) ? x^7 + x^2 + x + 1 : 0 [регулярно]. -******************************************************************************* -*/ - -void beltBlockMulC(u32 block[4]) -{ - register u32 t = ~((block[3] >> 31) - U32_1) & 0x00000087; - block[3] = (block[3] << 1) ^ (block[2] >> 31); - block[2] = (block[2] << 1) ^ (block[1] >> 31); - block[1] = (block[1] << 1) ^ (block[0] >> 31); - block[0] = (block[0] << 1) ^ t; - CLEAN(t); + return memSliceSize( + beltPolyMul_local(n), + ppMul_deep(n, n), + SIZE_MAX); } diff --git a/src/crypto/belt/belt_lcl.h b/src/crypto/belt/belt_lcl.h index 51346999..a2841854 100644 --- a/src/crypto/belt/belt_lcl.h +++ b/src/crypto/belt/belt_lcl.h @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): local definitions \project bee2 [cryptographic library] \created 2012.12.18 -\version 2020.03.20 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -35,169 +35,96 @@ extern "C" { /* ******************************************************************************* -Ускорители +Операции с блоками -Реализованы быстрые операции над блоками и полублоками belt. Блок -представляется либо как [16]octet, либо как [4]u32, -либо как [W_OF_B(128)]word. +Реализованы операции над блоками и полублоками belt. Блок представляется либо +как [16]octet, либо как [4]u32, либо как [W_OF_B(128)]word. Суффикс U32 в именах макросов и функций означает, что данные интерпретируются как массив u32. Суффикс W означает, что данные интерпретируются как массив word. + +\remark Блок не обязательно выровнен на границу word или u32. + +\todo Работу с блоками можно ускорить, если предположить выравнивание (в +качестве предусловия). + +\remark Функции beltBlockAddBitSizeU32() и beltHalfBlockAddBitSizeW() +нерегулярны. Однако регулярность не требуется, поскольку функции используются +только для обработки длин сообщений. ******************************************************************************* */ -#if (B_PER_W == 16) - #define beltBlockSetZero(block)\ - ((word*)(block))[0] = 0,\ - ((word*)(block))[1] = 0,\ - ((word*)(block))[2] = 0,\ - ((word*)(block))[3] = 0,\ - ((word*)(block))[4] = 0,\ - ((word*)(block))[5] = 0,\ - ((word*)(block))[6] = 0,\ - ((word*)(block))[7] = 0\ - -#define beltBlockRevW(block)\ - ((word*)(block))[0] = wordRev(((word*)(block))[0]),\ - ((word*)(block))[1] = wordRev(((word*)(block))[1]),\ - ((word*)(block))[2] = wordRev(((word*)(block))[2]),\ - ((word*)(block))[3] = wordRev(((word*)(block))[3]),\ - ((word*)(block))[4] = wordRev(((word*)(block))[4]),\ - ((word*)(block))[5] = wordRev(((word*)(block))[5]),\ - ((word*)(block))[6] = wordRev(((word*)(block))[6]),\ - ((word*)(block))[7] = wordRev(((word*)(block))[7])\ - -#define beltHalfBlockIsZero(block)\ - (((word*)(block))[0] == 0 && ((word*)(block))[1] == 0 &&\ - ((word*)(block))[2] == 0 && ((word*)(block))[3] == 0) + memSetZero(block, 16) #define beltBlockNeg(dest, src)\ - ((word*)(dest))[0] = ~((const word*)(src))[0],\ - ((word*)(dest))[1] = ~((const word*)(src))[1],\ - ((word*)(dest))[2] = ~((const word*)(src))[2],\ - ((word*)(dest))[3] = ~((const word*)(src))[3],\ - ((word*)(dest))[4] = ~((const word*)(src))[4],\ - ((word*)(dest))[5] = ~((const word*)(src))[5],\ - ((word*)(dest))[6] = ~((const word*)(src))[6],\ - ((word*)(dest))[7] = ~((const word*)(src))[7]\ + (memCopy(dest, src, 16), memNeg(dest, 16)) #define beltBlockXor(dest, src1, src2)\ - ((word*)(dest))[0] = ((const word*)(src1))[0] ^ ((const word*)(src2))[0],\ - ((word*)(dest))[1] = ((const word*)(src1))[1] ^ ((const word*)(src2))[1],\ - ((word*)(dest))[2] = ((const word*)(src1))[2] ^ ((const word*)(src2))[2],\ - ((word*)(dest))[3] = ((const word*)(src1))[3] ^ ((const word*)(src2))[3],\ - ((word*)(dest))[4] = ((const word*)(src1))[4] ^ ((const word*)(src2))[4],\ - ((word*)(dest))[5] = ((const word*)(src1))[5] ^ ((const word*)(src2))[5],\ - ((word*)(dest))[6] = ((const word*)(src1))[6] ^ ((const word*)(src2))[6],\ - ((word*)(dest))[7] = ((const word*)(src1))[7] ^ ((const word*)(src2))[7]\ + memXor(dest, src1, src2, 16) #define beltBlockXor2(dest, src)\ - ((word*)(dest))[0] ^= ((const word*)(src))[0],\ - ((word*)(dest))[1] ^= ((const word*)(src))[1],\ - ((word*)(dest))[2] ^= ((const word*)(src))[2],\ - ((word*)(dest))[3] ^= ((const word*)(src))[3],\ - ((word*)(dest))[4] ^= ((const word*)(src))[4],\ - ((word*)(dest))[5] ^= ((const word*)(src))[5],\ - ((word*)(dest))[6] ^= ((const word*)(src))[6],\ - ((word*)(dest))[7] ^= ((const word*)(src))[7]\ - -#define beltBlockCopy(dest, src)\ - ((word*)(dest))[0] = ((const word*)(src))[0],\ - ((word*)(dest))[1] = ((const word*)(src))[1],\ - ((word*)(dest))[2] = ((const word*)(src))[2],\ - ((word*)(dest))[3] = ((const word*)(src))[3],\ - ((word*)(dest))[4] = ((const word*)(src))[4],\ - ((word*)(dest))[5] = ((const word*)(src))[5],\ - ((word*)(dest))[6] = ((const word*)(src))[6],\ - ((word*)(dest))[7] = ((const word*)(src))[7]\ - -#elif (B_PER_W == 32) - -#define beltBlockSetZero(block)\ - ((word*)(block))[0] = 0,\ - ((word*)(block))[1] = 0,\ - ((word*)(block))[2] = 0,\ - ((word*)(block))[3] = 0\ - -#define beltBlockRevW(block)\ - ((word*)(block))[0] = wordRev(((word*)(block))[0]),\ - ((word*)(block))[1] = wordRev(((word*)(block))[1]),\ - ((word*)(block))[2] = wordRev(((word*)(block))[2]),\ - ((word*)(block))[3] = wordRev(((word*)(block))[3])\ + memXor2(dest, src, 16) #define beltHalfBlockIsZero(block)\ - (((word*)(block))[0] == 0 && ((word*)(block))[1] == 0)\ - -#define beltBlockNeg(dest, src)\ - ((word*)(dest))[0] = ~((const word*)(src))[0],\ - ((word*)(dest))[1] = ~((const word*)(src))[1],\ - ((word*)(dest))[2] = ~((const word*)(src))[2],\ - ((word*)(dest))[3] = ~((const word*)(src))[3]\ - -#define beltBlockXor(dest, src1, src2)\ - ((word*)(dest))[0] = ((const word*)(src1))[0] ^ ((const word*)(src2))[0],\ - ((word*)(dest))[1] = ((const word*)(src1))[1] ^ ((const word*)(src2))[1],\ - ((word*)(dest))[2] = ((const word*)(src1))[2] ^ ((const word*)(src2))[2],\ - ((word*)(dest))[3] = ((const word*)(src1))[3] ^ ((const word*)(src2))[3]\ - -#define beltBlockXor2(dest, src)\ - ((word*)(dest))[0] ^= ((const word*)(src))[0],\ - ((word*)(dest))[1] ^= ((const word*)(src))[1],\ - ((word*)(dest))[2] ^= ((const word*)(src))[2],\ - ((word*)(dest))[3] ^= ((const word*)(src))[3]\ + memIsZero(block, 8) #define beltBlockCopy(dest, src)\ - ((word*)(dest))[0] = ((const word*)(src))[0],\ - ((word*)(dest))[1] = ((const word*)(src))[1],\ - ((word*)(dest))[2] = ((const word*)(src))[2],\ - ((word*)(dest))[3] = ((const word*)(src))[3]\ + memCopy(dest, src, 16) -#elif (B_PER_W == 64) - -#define beltBlockSetZero(block)\ - ((word*)(block))[0] = 0,\ - ((word*)(block))[1] = 0\ - -#define beltBlockRevW(block)\ - ((word*)(block))[0] = wordRev(((word*)(block))[0]),\ - ((word*)(block))[1] = wordRev(((word*)(block))[1])\ +#if (B_PER_W == 16) -#define beltHalfBlockIsZero(block)\ - (((word*)(block))[0] == 0)\ +#define beltBlockRevW(block) {\ + ASSERT(memIsAligned(block, O_PER_W));\ + ((word*)(block))[0] = wordRev(((word*)(block))[0]);\ + ((word*)(block))[1] = wordRev(((word*)(block))[1]);\ + ((word*)(block))[2] = wordRev(((word*)(block))[2]);\ + ((word*)(block))[3] = wordRev(((word*)(block))[3]);\ + ((word*)(block))[4] = wordRev(((word*)(block))[4]);\ + ((word*)(block))[5] = wordRev(((word*)(block))[5]);\ + ((word*)(block))[6] = wordRev(((word*)(block))[6]);\ + ((word*)(block))[7] = wordRev(((word*)(block))[7]);\ +} -#define beltBlockNeg(dest, src)\ - ((word*)(dest))[0] = ~((const word*)(src))[0],\ - ((word*)(dest))[1] = ~((const word*)(src))[1]\ +#elif (B_PER_W == 32) -#define beltBlockXor(dest, src1, src2)\ - ((word*)(dest))[0] = ((const word*)(src1))[0] ^ ((const word*)(src2))[0],\ - ((word*)(dest))[1] = ((const word*)(src1))[1] ^ ((const word*)(src2))[1];\ +#define beltBlockRevW(block) {\ + ASSERT(memIsAligned(block, O_PER_W));\ + ((word*)(block))[0] = wordRev(((word*)(block))[0]);\ + ((word*)(block))[1] = wordRev(((word*)(block))[1]);\ + ((word*)(block))[2] = wordRev(((word*)(block))[2]);\ + ((word*)(block))[3] = wordRev(((word*)(block))[3]);\ +} -#define beltBlockXor2(dest, src)\ - ((word*)(dest))[0] ^= ((const word*)(src))[0],\ - ((word*)(dest))[1] ^= ((const word*)(src))[1]\ +#elif (B_PER_W == 64) -#define beltBlockCopy(dest, src)\ - ((word*)(dest))[0] = ((const word*)(src))[0],\ - ((word*)(dest))[1] = ((const word*)(src))[1]\ +#define beltBlockRevW(block) {\ + ASSERT(memIsAligned(block, O_PER_W));\ + ((word*)(block))[0] = wordRev(((word*)(block))[0]);\ + ((word*)(block))[1] = wordRev(((word*)(block))[1]);\ +} #else #error "Unsupported word size" #endif // B_PER_W -#define beltBlockRevU32(block)\ - ((u32*)(block))[0] = u32Rev(((u32*)(block))[0]),\ - ((u32*)(block))[1] = u32Rev(((u32*)(block))[1]),\ - ((u32*)(block))[2] = u32Rev(((u32*)(block))[2]),\ - ((u32*)(block))[3] = u32Rev(((u32*)(block))[3])\ +#define beltBlockRevU32(block) {\ + ASSERT(memIsAligned(block, 4));\ + ((u32*)(block))[0] = u32Rev(((u32*)(block))[0]);\ + ((u32*)(block))[1] = u32Rev(((u32*)(block))[1]);\ + ((u32*)(block))[2] = u32Rev(((u32*)(block))[2]);\ + ((u32*)(block))[3] = u32Rev(((u32*)(block))[3]);\ +} + +/* \brief block <- block + 8 * count */ +void beltBlockAddBitSizeU32(u32 block[4], size_t count); + +/* \brief block <- block + 8 * count */ +void beltHalfBlockAddBitSizeW(word block[W_OF_B(64)], size_t count); -#define beltBlockIncU32(block)\ - if ((((u32*)(block))[0] += 1) == 0 &&\ - (((u32*)(block))[1] += 1) == 0 &&\ - (((u32*)(block))[2] += 1) == 0)\ - ((u32*)(block))[3] += 1\ +/* \brief block(x) <- block(x) * x mod (x^128 + x^7 + x^2 + x + 1) */ +void beltBlockMulCU32(u32 block[4]); /* ******************************************************************************* @@ -227,13 +154,8 @@ typedef struct ******************************************************************************* */ -void beltBlockAddBitSizeU32(u32 block[4], size_t count); -void beltHalfBlockAddBitSizeW(word block[W_OF_B(64)], size_t count); void beltPolyMul(word c[], const word a[], const word b[], void* stack); size_t beltPolyMul_deep(); -void beltBlockMulC(u32 block[4]); - - #ifdef __cplusplus } /* extern "C" */ diff --git a/src/crypto/belt/belt_pbkdf.c b/src/crypto/belt/belt_pbkdf.c index 13205b7e..3cc717a7 100644 --- a/src/crypto/belt/belt_pbkdf.c +++ b/src/crypto/belt/belt_pbkdf.c @@ -4,7 +4,7 @@ \brief STB 34.101.31 (belt): PBKDF (password-based key derivation) \project bee2 [cryptographic library] \created 2012.12.18 -\version 2017.09.28 +\version 2025.10.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -25,7 +25,9 @@ err_t beltPBKDF2(octet key[32], const octet pwd[], size_t pwd_len, size_t iter, const octet salt[], size_t salt_len) { void* state; - octet* t; + octet* t; /* [32] */ + void* hmac_state; /* [beltHMAC_keep()] состояние после обработки pwd */ + void* hmac_state1; /* [beltHMAC_keep()] рабочая копия hmac_state */ // проверить входные данные if (iter == 0 || !memIsValid(pwd, pwd_len) || @@ -33,23 +35,28 @@ err_t beltPBKDF2(octet key[32], const octet pwd[], size_t pwd_len, !memIsValid(key, 32)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(beltHMAC_keep() + 32); + state = blobCreate2( + (size_t)32, + beltHMAC_keep(), + beltHMAC_keep(), + SIZE_MAX, + &t, &hmac_state, &hmac_state1); if (state == 0) return ERR_OUTOFMEMORY; - t = (octet*)state + beltHMAC_keep(); // key <- HMAC(pwd, salt || 00000001) - beltHMACStart(state, pwd, pwd_len); - beltHMACStepA(salt, salt_len, state); - *(u32*)key = 0, key[3] = 1; - beltHMACStepA(key, 4, state); - beltHMACStepG(key, state); + beltHMACStart(hmac_state, pwd, pwd_len); + memCopy(hmac_state1, hmac_state, beltHMAC_keep()); + beltHMACStepA(salt, salt_len, hmac_state1); + key[0] = key[1] = key[2] = key[3] = 0, key[3] = 1; + beltHMACStepA(key, 4, hmac_state1); + beltHMACStepG(key, hmac_state1); // пересчитать key memCopy(t, key, 32); while (--iter) { - beltHMACStart(state, pwd, pwd_len); - beltHMACStepA(t, 32, state); - beltHMACStepG(t, state); + memCopy(hmac_state1, hmac_state, beltHMAC_keep()); + beltHMACStepA(t, 32, hmac_state1); + beltHMACStepG(t, hmac_state1); memXor2(key, t, 32); } // завершить diff --git a/src/crypto/bign/bign_ec.c b/src/crypto/bign/bign_ec.c new file mode 100644 index 00000000..b6c35aef --- /dev/null +++ b/src/crypto/bign/bign_ec.c @@ -0,0 +1,94 @@ +/* +******************************************************************************* +\file bign_ec.c +\brief STB 34.101.45 (bign): curves +\project bee2 [cryptographic library] +\created 2012.04.27 +\version 2025.09.15 +\copyright The Bee2 authors +\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). +******************************************************************************* +*/ + +#include "bee2/core/err.h" +#include "bee2/core/blob.h" +#include "bee2/core/mem.h" +#include "bee2/core/util.h" +#include "bee2/math/gfp.h" +#include "bee2/math/ecp.h" +#include "bee2/math/ww.h" +#include "bee2/math/zz.h" +#include "bign_lcl.h" + +/* +******************************************************************************* +Создание эллиптической кривой +******************************************************************************* +*/ + +err_t bignEcCreate(ec_o** pec, const bign_params* params) +{ + size_t no, n; + size_t f_deep; + void* state; + ec_o* ec; /* [ecpCreateJ_keep(n)] */ + qr_o* f; /* [gfpCreate_keep(no)] */ + void* stack; + // pre + ASSERT(memIsValid(pec, sizeof(*pec))); + ASSERT(bignParamsCheck2(params) == ERR_OK); + // размерности + no = O_OF_B(2 * params->l); + n = W_OF_B(2 * params->l); + f_deep = gfpCreate_deep(no); + // создать состояние + state = blobCreate2( + ecpCreateJ_keep(n), + gfpCreate_keep(no), + SIZE_MAX, + &ec, &f); + if (state == 0) + return ERR_OUTOFMEMORY; + // создать стек + stack = blobCreate( + utilMax(3, + gfpCreate_deep(no), + ecpCreateJ_deep(n, f_deep), + ecGroupCreate_deep(f_deep))); + if (stack == 0) + { + blobClose(state); + return ERR_OUTOFMEMORY; + } + // создать поле, кривую и группу + if (!gfpCreate(f, params->p, no, stack) || + !ecpCreateJ(ec, f, params->a, params->b, stack) || + !ecGroupCreate(ec, 0, params->yG, params->q, no, 1, stack)) + { + blobClose(state); + blobClose(stack); + return ERR_BAD_PARAMS; + } + ASSERT(wwBitSize(f->mod, n) == params->l * 2); + ASSERT(wwGetBits(f->mod, 0, 2) == 3); + ASSERT(wwBitSize(ec->order, n) == params->l * 2); + ASSERT(zzIsOdd(ec->order, n)); + // присоединить f к ec + objAppend(ec, f, 0); + // завершение + blobClose(stack); + *pec = ec; + return ERR_OK; +} + +/* +******************************************************************************* +Закрытие эллиптической кривой +******************************************************************************* +*/ + +void bignEcClose(ec_o* ec) +{ + blobClose(ec); +} + diff --git a/src/crypto/bign/bign_ibs.c b/src/crypto/bign/bign_ibs.c index c3efa25c..27ff391e 100644 --- a/src/crypto/bign/bign_ibs.c +++ b/src/crypto/bign/bign_ibs.c @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): identity-based signature \project bee2 [cryptographic library] \created 2012.04.27 -\version 2023.09.20 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -28,65 +28,44 @@ ******************************************************************************* */ -static size_t bignIdExtract_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n) + - utilMax(2, - beltHash_keep(), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)); -} - -err_t bignIdExtract(octet id_privkey[], octet id_pubkey[], - const bign_params* params, const octet oid_der[], size_t oid_len, +err_t bignIdExtractEc(octet id_privkey[], octet id_pubkey[], + const ec_o* ec, const octet oid_der[], size_t oid_len, const octet id_hash[], const octet sig[], octet pubkey[]) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* Q; /* [2n] открытый ключ */ - word* R; /* [2n] точка R */ + word* Q; /* [2 * n] открытый ключ */ + word* R; /* [2 * n] точка R (|Q) */ word* H; /* [n] хэш-значение */ - word* s0; /* [n / 2 + 1] первая часть подписи */ + word* s0; /* [n / 2 + 1] первая часть подписи (|H) */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(id_hash, no) || !memIsValid(sig, no + no / 2) || + !memIsValid(pubkey, 2 * no) || !memIsValid(id_privkey, no) || + !memIsValid(id_pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignIdExtract_deep)); + state = blobCreate2( + O_OF_W(2 * n), + O_OF_W(2 * n) | SIZE_HI, + O_OF_W(n), + O_OF_W(n / 2 + 1) | SIZE_HI, + O_OF_W(n), + utilMax(2, + beltHash_keep(), + ecAddMulA_deep(n, ec->d, ec->deep, 2, n, n / 2 + 1)), + SIZE_MAX, + &Q, &R, &H, &s0, &s1, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(id_hash, no) || - !memIsValid(sig, no + no / 2) || - !memIsValid(pubkey, 2 * no) || - !memIsValid(id_privkey, no) || - !memIsValid(id_pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - Q = R = objEnd(ec, word); - H = s0 = Q + 2 * n; - s1 = H + n; - stack = (octet*)(s1 + n); // загрузить Q if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || !qrFrom(ecY(Q, n), pubkey + no, ec->f, stack)) @@ -125,16 +104,32 @@ err_t bignIdExtract(octet id_privkey[], octet id_pubkey[], beltHashStepH(oid_der, oid_len, stack); beltHashStepH(R, no, stack); beltHashStepH(id_hash, no, stack); - if (beltHashStepV2(sig, no / 2, stack)) + if (!beltHashStepV2(sig, no / 2, stack)) { - wwTo(id_privkey, no, s1); - memCopy(id_pubkey, R, no); - qrTo(id_pubkey + no, ecY(R, n), ec->f, stack); + blobClose(state); + return ERR_BAD_SIG; } - else - code = ERR_BAD_SIG; + wwTo(id_privkey, no, s1); + memCopy(id_pubkey, R, no); + qrTo(id_pubkey + no, ecY(R, n), ec->f, stack); // завершение blobClose(state); + return ERR_OK; +} + +err_t bignIdExtract(octet id_privkey[], octet id_pubkey[], + const bign_params* params, const octet oid_der[], size_t oid_len, + const octet id_hash[], const octet sig[], octet pubkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignIdExtractEc(id_privkey, id_pubkey, ec, oid_der, oid_len, + id_hash, sig, pubkey); + bignEcClose(ec); return code; } @@ -144,70 +139,47 @@ err_t bignIdExtract(octet id_privkey[], octet id_pubkey[], ******************************************************************************* */ -static size_t bignIdSign_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n) + - utilMax(4, - beltHash_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n)); -} - -err_t bignIdSign(octet id_sig[], const bign_params* params, - const octet oid_der[], size_t oid_len, const octet id_hash[], - const octet hash[], const octet id_privkey[], gen_i rng, void* rng_state) +err_t bignIdSignEc(octet id_sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet id_hash[], const octet hash[], + const octet id_privkey[], gen_i rng, void* rng_state) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* e; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* V; /* [2n] точка V */ - word* s0; /* [n/2] первая часть подписи */ + word* k; /* [n] одноразовый личный ключ ||e */ + word* V; /* [2 * n] точка V */ + word* s0; /* [n / 2] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(id_hash, no) || !memIsValid(hash, no) || + !memIsValid(id_privkey, no) || !memIsValid(id_sig, no + no / 2)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить rng if (rng == 0) return ERR_BAD_RNG; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignIdSign_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(n / 2), + utilMax(4, + beltHash_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n)), + SIZE_MAX, + &e, &s1, &k, &V, &s0, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(id_hash, no) || - !memIsValid(hash, no) || - !memIsValid(id_privkey, no) || - !memIsValid(id_sig, no + no / 2)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - e = s1 = objEnd(ec, word); - k = e + n; - V = k + n; - s0 = V + n + n / 2; - stack = (octet*)(V + 2 * n); // загрузить e wwFrom(e, id_privkey, no); if (wwCmp(e, ec->order, n) >= 0) @@ -247,79 +219,78 @@ err_t bignIdSign(octet id_sig[], const bign_params* params, zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(id_sig + no / 2, no, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } -static size_t bignIdSign2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bignIdSign(octet id_sig[], const bign_params* params, + const octet oid_der[], size_t oid_len, const octet id_hash[], + const octet hash[], const octet id_privkey[], gen_i rng, void* rng_state) { - return O_OF_W(4 * n) + beltHash_keep() + - utilMax(6, - beltHash_keep(), - 32, - beltWBL_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n)); + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignIdSignEc(id_sig, ec, oid_der, oid_len, id_hash, hash, + id_privkey, rng, rng_state); + bignEcClose(ec); + return code; } -err_t bignIdSign2(octet id_sig[], const bign_params* params, - const octet oid_der[], size_t oid_len, const octet id_hash[], - const octet hash[], const octet id_privkey[], const void* t, size_t t_len) +/* +******************************************************************************* +Детерминированная выработка идентификационной ЭЦП +******************************************************************************* +*/ + +err_t bignIdSign2Ec(octet id_sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet id_hash[], const octet hash[], + const octet id_privkey[], const void* t, size_t t_len) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* e; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* V; /* [2n] точка V */ - word* s0; /* [n/2] первая часть подписи */ + word* k; /* [n] одноразовый личный ключ (|e) */ + word* V; /* [2 * n] точка V */ + word* s0; /* [n / 2] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ octet* hash_state; /* [beltHash_keep] состояние хэширования */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(id_hash, no) || !memIsValid(hash, no) || + !memIsValid(id_privkey, no) || !memIsValid(id_sig, no + no / 2)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить t if (!memIsNullOrValid(t, t_len)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignIdSign2_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(n / 2), + beltHash_keep(), + utilMax(6, + beltHash_keep(), + 32, + beltWBL_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n)), + SIZE_MAX, + &e, &s1, &k, &V, &s0, &hash_state, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(id_hash, no) || - !memIsValid(hash, no) || - !memIsValid(id_privkey, no) || - !memIsValid(id_sig, no + no / 2)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - e = s1 = objEnd(ec, word); - k = e + n; - V = k + n; - s0 = V + n + n / 2; - hash_state = (octet*)(V + 2 * n); - stack = hash_state + beltHash_keep(); // загрузить e wwFrom(e, id_privkey, no); if (wwCmp(e, ec->order, n) >= 0) @@ -376,86 +347,81 @@ err_t bignIdSign2(octet id_sig[], const bign_params* params, zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(id_sig + no / 2, no, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } +err_t bignIdSign2(octet id_sig[], const bign_params* params, + const octet oid_der[], size_t oid_len, const octet id_hash[], + const octet hash[], const octet id_privkey[], const void* t, size_t t_len) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignIdSign2Ec(id_sig, ec, oid_der, oid_len, id_hash, hash, + id_privkey, t, t_len); + bignEcClose(ec); + return code; +} + /* ******************************************************************************* Проверка идентификационной ЭЦП ******************************************************************************* */ -static size_t bignIdVerify_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(7 * n + 2) + beltHash_keep() + - utilMax(5, - beltHash_keep(), - ecpIsOnA_deep(n, f_deep), - zzMul_deep(n / 2, n / 2), - zzMod_deep(n + 1, n), - ecAddMulA_deep(n, ec_d, ec_deep, 3, n, n / 2 + 1, n)); -} - -err_t bignIdVerify(const bign_params* params, const octet oid_der[], - size_t oid_len, const octet id_hash[], const octet hash[], - const octet id_sig[], const octet id_pubkey[], const octet pubkey[]) +err_t bignIdVerifyEc(const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet id_hash[], const octet hash[], const octet id_sig[], + const octet id_pubkey[], const octet pubkey[]) { err_t code; size_t no, n; - // состояние (буферы R и V совпадают) void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* R; /* [2n] открытый ключ R */ - word* Q; /* [2n] открытый ключ Q */ - word* V; /* [2n] точка V (V == R) */ + word* R; /* [2 * n] открытый ключ R */ + word* Q; /* [2 * n] открытый ключ Q (|R) */ + word* V; /* [2 * n] точка V (V == R) */ word* s0; /* [n / 2 + 1] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ word* t; /* [n / 2] переменная t */ word* t1; /* [n + 1] произведение (s0 + 2^l)(t + 2^l) */ octet* hash_state; /* [beltHash_keep] состояние хэширования */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(id_hash, no) || !memIsValid(hash, no) || + !memIsValid(id_sig, no + no / 2) || !memIsValid(id_pubkey, 2 * no) || + !memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignIdVerify_deep)); + state = blobCreate2( + O_OF_W(2 * n), + O_OF_W(2 * n) | SIZE_HI, + O_OF_W(2 * n), + O_OF_W(n / 2 + 1), + O_OF_W(n), + O_OF_W(n / 2), + O_OF_W(n + 1), + beltHash_keep(), + utilMax(5, + beltHash_keep(), + ecpIsOnA_deep(n, ec->f->deep), + zzMul_deep(n / 2, n / 2), + zzMod_deep(n + 1, n), + ecAddMulA_deep(n, ec->d, ec->deep, 3, n, n / 2 + 1, n)), + SIZE_MAX, + &R, &V, &Q, &s0, &s1, &t, &t1, &hash_state, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(id_hash, no) || - !memIsValid(hash, no) || - !memIsValid(id_sig, no + no / 2) || - !memIsValid(id_pubkey, 2 * no) || - !memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - R = V = objEnd(ec, word); - Q = R + 2 * n; - s0 = Q + 2 * n; - s1 = s0 + n / 2 + 1; - t = s1 + n; - t1 = t + n / 2; - hash_state = (octet*)(t1 + n + 1); - stack = hash_state + beltHash_keep(); // загрузить R if (!qrFrom(ecX(R), id_pubkey, ec->f, stack) || !qrFrom(ecY(R, n), id_pubkey + no, ec->f, stack) || @@ -523,3 +489,19 @@ err_t bignIdVerify(const bign_params* params, const octet oid_der[], blobClose(state); return code; } + +err_t bignIdVerify(const bign_params* params, const octet oid_der[], + size_t oid_len, const octet id_hash[], const octet hash[], + const octet id_sig[], const octet id_pubkey[], const octet pubkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignIdVerifyEc(ec, oid_der, oid_len, id_hash, hash, id_sig, + id_pubkey, pubkey); + bignEcClose(ec); + return code; +} diff --git a/src/crypto/bign/bign_keyt.c b/src/crypto/bign/bign_keyt.c index d9cf2e93..47d8ca7c 100644 --- a/src/crypto/bign/bign_keyt.c +++ b/src/crypto/bign/bign_keyt.c @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): key transport \project bee2 [cryptographic library] \created 2012.04.27 -\version 2025.05.07 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -30,64 +30,39 @@ ******************************************************************************* */ -static size_t bignKeyWrap_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + 32 + - utilMax(2, - ecMulA_deep(n, ec_d, ec_deep, n), - beltKWP_keep()); -} - -err_t bignKeyWrap(octet token[], const bign_params* params, const octet key[], +err_t bignKeyWrapEc(octet token[], const ec_o* ec, const octet key[], size_t len, const octet header[16], const octet pubkey[], gen_i rng, void* rng_state) { - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ word* k; /* [n] одноразовый личный ключ */ - word* R; /* [2n] точка R */ + word* R; /* [2 * n] точка R */ octet* theta; /* [32] ключ защиты */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(pubkey, 2 * no) || !memIsValid(token, 16 + no + len)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить rng if (rng == 0) return ERR_BAD_RNG; - // проверить header и key - if (len < 16 || - !memIsValid(key, len) || - !memIsNullOrValid(header, 16)) + if (len < 16 || !memIsValid(key, len) || !memIsNullOrValid(header, 16)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignKeyWrap_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(2 * n), + (size_t)32, + utilMax(2, + ecMulA_deep(n, ec->d, ec->deep, n), + beltKWP_keep()), + SIZE_MAX, + &k, &R, &theta, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(pubkey, 2 * no) || - !memIsValid(token, 16 + no + len)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - k = objEnd(ec, word); - R = k + n; - theta = (octet*)(R + 2 * n); - stack = theta + 32; // сгенерировать k if (!zzRandNZMod(k, ec->order, n, rng, rng_state)) { @@ -128,86 +103,70 @@ err_t bignKeyWrap(octet token[], const bign_params* params, const octet key[], beltKWPStepE(token + no, len + 16, stack); // доопределить токен memCopy(token, R, no); - // все нормально + // завершение blobClose(state); return ERR_OK; } +err_t bignKeyWrap(octet token[], const bign_params* params, const octet key[], + size_t len, const octet header[16], const octet pubkey[], gen_i rng, + void* rng_state) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeyWrapEc(token, ec, key, len, header, pubkey, rng, rng_state); + bignEcClose(ec); + return code; +} + /* ******************************************************************************* Разбор токена ******************************************************************************* */ -static size_t bignKeyUnwrap_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return MAX2(O_OF_W(5 * n), 32 + 16) + - utilMax(3, - beltKWP_keep(), - qrPower_deep(n, n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n)); -} - -err_t bignKeyUnwrap(octet key[], const bign_params* params, const octet token[], +err_t bignKeyUnwrapEc(octet key[], const ec_o* ec, const octet token[], size_t len, const octet header[16], const octet privkey[]) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* R; /* [2n] точка R */ + word* R; /* [2 * n] точка R */ word* t1; /* [n] вспомогательное число */ word* t2; /* [n] вспомогательное число */ octet* theta; /* [32] ключ защиты */ octet* header2; /* [16] заголовок2 */ void* stack; /* граница стека */ - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить token и header - if (!memIsValid(token, len) || - !memIsNullOrValid(header, 16)) - return ERR_BAD_INPUT; - // создать состояние - state = blobCreate(bignStart_keep(params->l, bignKeyUnwrap_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; + // pre + ASSERT(ecIsOperable(ec)); // размерности - no = ec->f->no; - n = ec->f->n; - // проверить длину токена + no = ec->f->no, n = ec->f->n; + // входной контроль if (len < 32 + no) - { - blobClose(state); return ERR_BAD_KEYTOKEN; - } - // проверить входные указатели - if (!memIsValid(privkey, no) || - !memIsValid(key, len - 16 - no)) - { - blobClose(state); + if (!memIsValid(token, len) || !memIsNullOrValid(header, 16) || + !memIsValid(privkey, no) || !memIsValid(key, len - 16 - no)) return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - R = d + n; - t1 = R + 2 * n; - t2 = t1 + n; - theta = (octet*)d; - header2 = theta + 32; - if (5 * no >= 48) - stack = t2 + n; - else - stack = header2 + 16; + // создать состояние + state = blobCreate2( + O_OF_W(n), + (size_t)32, + O_OF_W(2 * n), + O_OF_W(n), + O_OF_W(n), + (size_t)16, + utilMax(3, + beltKWP_keep(), + qrPower_deep(n, n, ec->f->deep), + ecMulA_deep(n, ec->d, ec->deep, n)), + SIZE_MAX, + &d, &theta, &R, &t1, &t2, &header2, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // загрузить d wwFrom(d, privkey, no); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -258,9 +217,23 @@ err_t bignKeyUnwrap(octet key[], const bign_params* params, const octet token[], header == 0 && !memIsZero(header2, 16)) { memSetZero(key, len - no - 16); - code = ERR_BAD_KEYTOKEN; + return ERR_BAD_KEYTOKEN; } // завершение blobClose(state); + return ERR_OK; +} + +err_t bignKeyUnwrap(octet key[], const bign_params* params, const octet token[], + size_t len, const octet header[16], const octet privkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeyUnwrapEc(key, ec, token, len, header, privkey); + bignEcClose(ec); return code; } diff --git a/src/crypto/bign/bign_lcl.h b/src/crypto/bign/bign_lcl.h index 5a8ef411..4b7809b3 100644 --- a/src/crypto/bign/bign_lcl.h +++ b/src/crypto/bign/bign_lcl.h @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): local declarations \project bee2 [cryptographic library] \created 2014.04.03 -\version 2025.04.25 +\version 2025.09.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -21,48 +21,176 @@ extern "C" { /* ******************************************************************************* -Эллиптические кривые СТБ 34.101.45 могут использоваться в других модулях. -Определения, даваемые ниже, позволяют использовать низкоуровневые функции bign, -предназначенные для управления эллиптической кривой. +В основных функциях, объявленных в bign.h, параметры эллиптической кривой +передаются через структуру params типа bign_params. По параметрам params +строится кривая ec, именно она используется в дальнейших вычислениях. +Эти вычисления оформлены в виде EC-функций, которые сопровождают основные. +EC-функция повторяет интерфейс основной, только на ее вход вместо params +передается ec. Имя EC-функции получается из имени основной добавлением +суффикса "Ec". + +Общая схема построения основной функции bignXXX(): +1. Проверить params с помощью функции bignParamsCheck(). +2. По params построить ec с помощью функции bignEcCreate(). +3. Выполнить Ec-функцию bignXXXEc(), передавая ec ей на вход. +4. Завершить работу с ec c помощью функции bignEcClose(). +5. Возвратить результаты работы bignXXXEc(). + +EC-функции имеют самостоятельное значение. Их можно использовать напрямую +в тех случаях, когда кривая ec уже создана к моменту вызова. + +\remark EC-функции могут работать на уровнях стойкости l, отличных от трех +стандартных (l == 128 || l == 192 || l == 256). Для этого необходимо +(но не обязательно достаточно), чтобы уровень l был кратен длине машинного +слова в битах: + l % B_PER_W == 0. +Последнее условие проверяется в функции bignParamsCheck2(), которая является +ослабленной редакцией bignParamsCheck(). ******************************************************************************* */ -/*! \brief Проверка работоспособности параметров +/*! \brief Предварительная проверка параметров - Проводится минимальная проверка работоспособности параметров params, - обеспечивающая работоспобность высокоуровневых функций. Конкретнее, - проверяется выполнение следующих ограничений на поля params: + Проводится предварительная проверка параметров params, обеспечивающая + работоспобность высокоуровневых функций. Конкретнее, проверяется выполнение + следующих ограничений на поля params: + - указатель params корректен; - l == 128 || l == 192 || l == 256; + - l % B_PER_W == 0; - p и q -- 2l-битовые нечетные числа; - p[0] % 4 == 3; - a != 0 и b != 0; - неиспользуемые октеты p, a, b, yG обнулены. \return ERR_OK в случае успеха и код ошибки в противном случае. + \remark Условие l % B_PER_W == 0 является ограничением реализации + (не обременительным). При нарушении условия возвращается код ошибки + ERR_NOT_IMPLEMENTED. */ +err_t bignParamsCheck( + const bign_params* params /*!< [in] долговременные параметры */ +); + +/*! \brief Ослабленная предварительная проверка параметров -bool_t bignIsOperable( + Проводится ослабленная предварительная проверка параметров params. + Проверяются условия функции bignParamsCheck() с заменой условий + - l == 128 || l == 192 || l == 256; + - l % B_PER_W == 0; + на условие + - (2 * l) % B_PER_W == 0. + \return ERR_OK в случае успеха и код ошибки в противном случае. +*/ +err_t bignParamsCheck2( + const bign_params* params /*!< [in] долговременные параметры */ +); + +/*! \brief Создание эллиптической кривой + + По долговременным параметрам params создается эллиптическая кривая. + Описание кривой возвращается по адресу *pec. + \pre Указатель pec корректен. + \pre bignParamsCheck2(params) == ERR_OK. + \return ERR_OK, если кривая успешно создана, и код ошибки в противном случае. + \remark Проводится минимальная проверка параметров, обеспечивающая + работоспособность высокоуровневых функций. +*/ +err_t bignEcCreate( + ec_o** pec, /*!< [out] эллиптическая кривая */ const bign_params* params /*!< [in] долговременные параметры */ ); -/*! \brief Потребности в стеке +/*! \brief Закрытие эллиптической кривой + + Эллиптическая кривая ec закрывается. +*/ +void bignEcClose( + ec_o* ec /*!< [in] эллиптическая кривая */ +); + +/* +******************************************************************************* +ЕС-функции + +\expect Кривая ec создана с помощью bignEcCreate(). +\remark В функции bignParamsValEc() в отличие от всех остальных кривая ec +не заменяет параметры params, а используется вместе с ними. +******************************************************************************* +*/ + +err_t bignParamsValEc(const ec_o* ec, const bign_params* params); + +err_t bignKeypairGenEc(octet privkey[], octet pubkey[], const ec_o* ec, + gen_i rng, void* rng_state); - Определяется глубина стека, который требуется высокоуровневой функции - для работы с эллиптической кривой, описываемой объясненными ниже - размерностями n, f_deep, ec_d, ec_deep. - \remark При расчете глубины не следует учитывать память для +err_t bignKeypairValEc(const ec_o* ec, const octet privkey[], + const octet pubkey[]); + +err_t bignPubkeyValEc(const ec_o* ec, const octet pubkey[]); + +err_t bignPubkeyCalcEc(octet pubkey[], const ec_o* ec, const octet privkey[]); + +err_t bignDHEc(octet key[], const ec_o* ec, const octet privkey[], + const octet pubkey[], size_t key_len); + +err_t bignSignEc(octet sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet hash[], const octet privkey[], gen_i rng, + void* rng_state); + +err_t bignSign2Ec(octet sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet hash[], const octet privkey[], const void* t, + size_t t_len); + +err_t bignVerifyEc(const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet hash[], const octet sig[], const octet pubkey[]); + +err_t bignKeyWrapEc(octet token[], const ec_o* ec, const octet key[], + size_t len, const octet header[16], const octet pubkey[], + gen_i rng, void* rng_state); + +err_t bignKeyUnwrapEc(octet key[], const ec_o* ec, const octet token[], + size_t len, const octet header[16], const octet privkey[]); + +err_t bignIdExtractEc(octet id_privkey[], octet id_pubkey[], + const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet id_hash[], const octet sig[], octet pubkey[]); + +err_t bignIdSignEc(octet id_sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet id_hash[], const octet hash[], + const octet id_privkey[], gen_i rng, void* rng_state); + +err_t bignIdSign2Ec(octet id_sig[], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet id_hash[], const octet hash[], + const octet id_privkey[], const void* t, size_t t_len); + +err_t bignIdVerifyEc(const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet id_hash[], const octet hash[], const octet id_sig[], + const octet id_pubkey[], const octet pubkey[]); + +/* +******************************************************************************* +К удалению +******************************************************************************* +*/ + +/*! \brief Потребности в стеке + + Определяется глубина стека, который требуется высокоуровневой функции + для работы с эллиптической кривой, описываемой объясненными ниже + размерностями n, f_deep, ec_d, ec_deep. + \remark При расчете глубины не следует учитывать память для размещения описаний базового поля и эллиптической кривой. */ -typedef size_t (*bign_deep_i)( +typedef size_t(*bign_deep_i)( size_t n, /*!< [in] число слов для хранения элемента поля */ size_t f_deep, /*!< [in] глубина стека базового поля */ size_t ec_d, /*!< [in] число проективных координат */ size_t ec_deep /*!< [in] глубина стека эллиптической кривой */ -); + ); /*! \brief Длина состояния - Возвращается длина состояния (в октетах) высокоуровневой функции, + Возвращается длина состояния (в октетах) высокоуровневой функции, которая работает на уровне стойкости l и имеет потребности в стеке deep. \pre l == 128 || l == 192 || l == 256. \return Длина состояния. @@ -75,15 +203,15 @@ size_t bignStart_keep( /*! \brief Начало работы с параметрами - По долговременным параметрам params по адресу state формируется описание + По долговременным параметрам params по адресу state формируется описание эллиптической кривой. - \pre bignIsOperable(params). - \return ERR_OK, если описание успешно создано, и код ошибки в противном + \pre bignParamsCheck(params) == ERR_OK. + \return ERR_OK, если описание успешно создано, и код ошибки в противном случае. \remark Высокоуровневый механизм должен работать по следующей схеме: - описать потребности в стеке с помощью функции интерфейса bign_deep_i; - определить длину состояния, вызвав bignStart_keep(); - - определить начало стека как память в state сразу после описания + - определить начало стека как память в state сразу после описания эллиптической кривой. . */ @@ -92,6 +220,7 @@ err_t bignStart( const bign_params* params /*!< [in] долговременные параметры */ ); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/crypto/bign/bign_misc.c b/src/crypto/bign/bign_misc.c index 7f8b5164..ca0dfe6b 100644 --- a/src/crypto/bign/bign_misc.c +++ b/src/crypto/bign/bign_misc.c @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): miscellaneous (OIDs, keys, DH) \project bee2 [cryptographic library] \created 2012.04.27 -\version 2023.09.22 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -55,53 +55,32 @@ err_t bignOidToDER(octet der[], size_t* count, const char* oid) ******************************************************************************* */ -static size_t bignKeypairGen_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bignKeypairGenEc(octet privkey[], octet pubkey[], const ec_o* ec, + gen_i rng, void* rng_state) { - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - -err_t bignKeypairGen(octet privkey[], octet pubkey[], - const bign_params* params, gen_i rng, void* rng_state) -{ - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ + word* Q; /* [2 * n] открытый ключ */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить rng if (rng == 0) return ERR_BAD_RNG; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignKeypairGen_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(2 * n), + ecMulA_deep(n, ec->d, ec->deep, n), + SIZE_MAX, + &d, &Q, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; // d <-R {1,2,..., q - 1} if (!zzRandNZMod(d, ec->f->mod, n, rng, rng_state)) { @@ -109,146 +88,155 @@ err_t bignKeypairGen(octet privkey[], octet pubkey[], return ERR_BAD_RNG; } // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) + if (!ecMulA(Q, ec->base, ec, d, n, stack)) { - // выгрузить ключи - wwTo(privkey, no, d); - qrTo(pubkey, ecX(Q), ec->f, stack); - qrTo(pubkey + no, ecY(Q, n), ec->f, stack); + blobClose(state); + return ERR_BAD_PARAMS; } - else - code = ERR_BAD_PARAMS; + // выгрузить ключи + wwTo(privkey, no, d); + qrTo(pubkey, ecX(Q), ec->f, stack); + qrTo(pubkey + no, ecY(Q, n), ec->f, stack); // завершение blobClose(state); + return ERR_OK; +} + +err_t bignKeypairGen(octet privkey[], octet pubkey[], + const bign_params* params, gen_i rng, void* rng_state) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeypairGenEc(privkey, pubkey, ec, rng, rng_state); + bignEcClose(ec); return code; } /* ******************************************************************************* -Проверка ключей +Проверка пары ключей ******************************************************************************* */ -static size_t bignKeypairVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - -err_t bignKeypairVal(const bign_params* params, const octet privkey[], +err_t bignKeypairValEc(const ec_o* ec, const octet privkey[], const octet pubkey[]) { - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ + word* Q; /* [2 * n] открытый ключ */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignKeypairVal_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(2 * n), + ecMulA_deep(n, ec->d, ec->deep, n), + SIZE_MAX, + &d, &Q, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; // d <- privkey wwFrom(d, privkey, no); // 0 < d < q? - wwFrom(Q, params->q, no); - if (wwIsZero(d, n) || wwCmp(d, Q, n) >= 0) + if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) { blobClose(state); return ERR_BAD_PRIVKEY; } // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) + if (!ecMulA(Q, ec->base, ec, d, n, stack)) { - // Q == pubkey? - wwTo(Q, 2 * no, Q); - if (!memEq(Q, pubkey, 2 * no)) - code = ERR_BAD_PUBKEY; + blobClose(state); + return ERR_BAD_PARAMS; + } + // Q == pubkey? + wwTo(Q, 2 * no, Q); + if (!memEq(Q, pubkey, 2 * no)) + { + blobClose(state); + return ERR_BAD_PUBKEY; } - else - code = ERR_BAD_PARAMS; // завершение blobClose(state); - return code; + return ERR_OK; } -static size_t bignPubkeyVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bignKeypairVal(const bign_params* params, const octet privkey[], + const octet pubkey[]) { - return O_OF_W(2 * n) + - ecpIsOnA_deep(n, f_deep); + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeypairValEc(ec, privkey, pubkey); + bignEcClose(ec); + return code; } -err_t bignPubkeyVal(const bign_params* params, const octet pubkey[]) +/* +******************************************************************************* +Проверка открытого ключа +******************************************************************************* +*/ + +err_t bignPubkeyValEc(const ec_o* ec, const octet pubkey[]) { - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* Q; /* [2n] открытый ключ */ + word* Q; /* [2 * n] открытый ключ */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignPubkeyVal_deep)); + state = blobCreate2( + O_OF_W(2 * n), + ecpIsOnA_deep(n, ec->f->deep), + SIZE_MAX, + &Q, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - Q = objEnd(ec, word); - stack = Q + 2 * n; // загрузить pt + // Q \in ec? if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || - !qrFrom(ecY(Q, n), pubkey + no, ec->f, stack)) + !qrFrom(ecY(Q, n), pubkey + no, ec->f, stack) || + !ecpIsOnA(Q, ec, stack)) { blobClose(state); return ERR_BAD_PUBKEY; } - // Q \in ec? - code = ecpIsOnA(Q, ec, stack) ? ERR_OK : ERR_BAD_PUBKEY; // завершение blobClose(state); + return ERR_OK; +} + +err_t bignPubkeyVal(const bign_params* params, const octet pubkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignPubkeyValEc(ec, pubkey); + bignEcClose(ec); return code; } @@ -258,50 +246,29 @@ err_t bignPubkeyVal(const bign_params* params, const octet pubkey[]) ******************************************************************************* */ -static size_t bignPubkeyCalc_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - -err_t bignPubkeyCalc(octet pubkey[], const bign_params* params, - const octet privkey[]) +err_t bignPubkeyCalcEc(octet pubkey[], const ec_o* ec, const octet privkey[]) { - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ + word* Q; /* [2 * n] открытый ключ */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignPubkeyCalc_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(2 * n), + ecMulA_deep(n, ec->d, ec->deep, n), + SIZE_MAX, + &d, &Q, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; // загрузить d wwFrom(d, privkey, no); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -310,16 +277,30 @@ err_t bignPubkeyCalc(octet pubkey[], const bign_params* params, return ERR_BAD_PRIVKEY; } // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) + if (!ecMulA(Q, ec->base, ec, d, n, stack)) { - // выгрузить открытый ключ - qrTo(pubkey, ecX(Q), ec->f, stack); - qrTo(pubkey + no, ecY(Q, n), ec->f, stack); + blobClose(state); + return ERR_BAD_PARAMS; } - else - code = ERR_BAD_PARAMS; + // выгрузить открытый ключ + qrTo(pubkey, ecX(Q), ec->f, stack); + qrTo(pubkey + no, ecY(Q, n), ec->f, stack); // завершение blobClose(state); + return ERR_OK; +} + +err_t bignPubkeyCalc(octet pubkey[], const bign_params* params, + const octet privkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignPubkeyCalcEc(pubkey, ec, privkey); + bignEcClose(ec); return code; } @@ -329,87 +310,81 @@ err_t bignPubkeyCalc(octet pubkey[], const bign_params* params, ******************************************************************************* */ -static size_t bignDH_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - utilMax(2, - ecpIsOnA_deep(n, f_deep), - ecMulA_deep(n, ec_d, ec_deep, n)); -} - -err_t bignDH(octet key[], const bign_params* params, const octet privkey[], +err_t bignDHEc(octet key[], const ec_o* ec, const octet privkey[], const octet pubkey[], size_t key_len) { - err_t code; size_t no, n; - // состояние void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ + word* u; /* [n] личный ключ */ + octet* K; /* [no] координаты общего ключа (|u) */ + word* V; /* [2 * n] открытый ключ */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + // входной контроль + if (!memIsValid(privkey, no) || !memIsValid(pubkey, 2 * no) || + !memIsValid(key, key_len)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; + if (key_len > 2 * no) + return ERR_BAD_SHAREDKEY; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignDH_deep)); + state = blobCreate2( + O_OF_W(n), + no | SIZE_HI, + O_OF_W(2 * n), + utilMax(2, + ecpIsOnA_deep(n, ec->f->deep), + ecMulA_deep(n, ec->d, ec->deep, n)), + SIZE_MAX, + &u, &K, &V, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // проверить длину key - if (key_len > 2 * no) + // загрузить u + wwFrom(u, privkey, no); + if (wwIsZero(u, n) || wwCmp(u, ec->order, n) >= 0) { blobClose(state); - return ERR_BAD_SHAREDKEY; + return ERR_BAD_PRIVKEY; } - // проверить входные указатели - if (!memIsValid(privkey, no) || - !memIsValid(pubkey, 2 * no) || - !memIsValid(key, key_len)) + // загрузить V + if (!qrFrom(ecX(V), pubkey, ec->f, stack) || + !qrFrom(ecY(V, n), pubkey + no, ec->f, stack) || + !ecpIsOnA(V, ec, stack)) { blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; - // загрузить d - wwFrom(d, privkey, no); - if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) - { - blobClose(state); - return ERR_BAD_PRIVKEY; + return ERR_BAD_PUBKEY; } - // загрузить Q - if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || - !qrFrom(ecY(Q, n), pubkey + no, ec->f, stack) || - !ecpIsOnA(Q, ec, stack)) + // V <- u V + if (!ecMulA(V, V, ec, u, n, stack)) { blobClose(state); - return ERR_BAD_PUBKEY; + return ERR_BAD_PARAMS; } - // Q <- d Q - if (ecMulA(Q, Q, ec, d, n, stack)) + // выгрузить общий ключ + qrTo(K, ecX(V), ec->f, stack); + memCopy(key, K, MIN2(key_len, no)); + if (key_len > no) { - // выгрузить общий ключ - qrTo((octet*)Q, ecX(Q), ec->f, stack); - if (key_len > no) - qrTo((octet*)Q + no, ecY(Q, n), ec->f, stack); - memCopy(key, Q, key_len); + qrTo(K, ecY(V, n), ec->f, stack); + memCopy(key + no, K, key_len - no); } - else - code = ERR_BAD_PARAMS; // завершение blobClose(state); + return ERR_OK; +} + +err_t bignDH(octet key[], const bign_params* params, const octet privkey[], + const octet pubkey[], size_t key_len) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignDHEc(key, ec, privkey, pubkey, key_len); + bignEcClose(ec); return code; } diff --git a/src/crypto/bign/bign_params.c b/src/crypto/bign/bign_params.c index 80af0b36..6d4f39c5 100644 --- a/src/crypto/bign/bign_params.c +++ b/src/crypto/bign/bign_params.c @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): public parameters \project bee2 [cryptographic library] \created 2012.04.27 -\version 2025.05.07 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -235,24 +235,68 @@ err_t bignParamsStd(bign_params* params, const char* name) return ERR_FILE_NOT_FOUND; } +/* +******************************************************************************* +Предварительная проверка параметров +******************************************************************************* +*/ + +err_t bignParamsCheck2(const bign_params* params) +{ + size_t no; + // корректный указатель? + if (!memIsValid(params, sizeof(bign_params))) + return ERR_BAD_INPUT; + // l % B_PER_W == 0? + if (2 * params->l % B_PER_W) + return ERR_NOT_IMPLEMENTED; + // p mod 4 == 3? q mod 2 == 1? + // p и q -- 2l-битовые? + // a != 0? b != 0? + // неиспользуемые октеты обнулены? + return + (no = O_OF_B(2 * params->l)) && + params->p[0] % 4 == 3 && params->q[0] % 2 == 1 && + params->p[no - 1] >= 128 && params->q[no - 1] >= 128 && + memIsZero(params->p + no, sizeof(params->p) - no) && + !memIsZero(params->a, no) && + !memIsZero(params->b, no) && + memIsZero(params->a + no, sizeof(params->a) - no) && + memIsZero(params->b + no, sizeof(params->b) - no) && + memIsZero(params->q + no, sizeof(params->q) - no) && + memIsZero(params->yG + no, sizeof(params->yG) - no) ? + ERR_OK : ERR_BAD_PARAMS; +} + +err_t bignParamsCheck(const bign_params* params) +{ + err_t code; + code = bignParamsCheck2(params); + ERR_CALL_CHECK(code); + if (params->l % B_PER_W) + return ERR_NOT_IMPLEMENTED; + return (params->l == 128 || params->l == 192 || params->l == 256) ? + ERR_OK : ERR_BAD_PARAMS; +} + /* ******************************************************************************* Проверка параметров --# l \in {128, 192, 256} (bignIsOperable) --# 2^{l - 1} < p, q < 2^l (bignIsOperable) --# p \equiv 3 \mod 4 (bignIsOperable) --# 0 < a (bignIsOperable) --# 0 < b (bignIsOperable, zzJacobi) +-# l \in {128, 192, 256} (bignParamsCheck) +-# 2^{l - 1} < p, q < 2^l (bignParamsCheck) +-# p \equiv 3 \mod 4 (bignParamsCheck) +-# 0 < a (bignParamsCheck) +-# 0 < b (bignParamsCheck, zzJacobi) -# p -- простое (ecpIsValid) --# q -- простое (ecpIsSafeGroup) --# q != p (ecpIsSafeGroup) --# p^m \not\equiv 1 (mod q), m = 1, 2,..., 50 (ecpIsSafeGroup) --# a, b < p (ecpCreateJ in bignStart) --# b \equiv B (mod p) (bignValParams) +-# q -- простое (ecpGroupIsSafe) +-# q != p (ecpGroupIsSafe) +-# p^m \not\equiv 1 (mod q), m = 1, 2,..., 50 (ecpGroupIsSafe) +-# a, b < p (ecpCreateJ in bignEcCreate) +-# b \equiv B (mod p) (bignParamsVal) -# 4a^3 + 27b^2 \not\equiv 0 (\mod p) (ecpIsValid) -# (b / p) = 1 (zzJacobi) --# G = (0, b^{(p + 1) /4}) (bignValParams) +-# G = (0, b^{(p + 1) /4}) (bignParamsVal) -# qG = O (ecpHasOrder) ******************************************************************************* */ @@ -267,51 +311,37 @@ static void bignSeedInc(octet seed[8]) CLEAN(carry); } -static size_t bignParamsVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return beltHash_keep() + O_OF_B(512) + - utilMax(6, - beltHash_keep(), - ecpIsValid_deep(n, f_deep), - ecpIsSafeGroup_deep(n), - ecpIsOnA_deep(n, f_deep), - qrPower_deep(n, n, f_deep), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); -} - -err_t bignParamsVal(const bign_params* params) +err_t bignParamsValEc(const ec_o* ec, const bign_params* params) { - err_t code; + err_t code = ERR_OK; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ octet* hash_state; /* [beltHash_keep] состояние хэширования */ octet* seed; /* [8] копия seed */ - word* B; /* [W_OF_B(512)] переменная B */ + octet* B; /* [64] переменная B */ + word* b; /* [W_OF_O(64)] коэффициент b (|B) */ void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignParamsVal_deep)); + state = blobCreate2( + beltHash_keep(), + (size_t)8, + (size_t)64, + W_OF_O(64) | SIZE_HI, + utilMax(6, + beltHash_keep(), + ecpIsValid_deep(n, ec->f->deep), + ecpGroupIsSafe_deep(n), + ecpIsOnA_deep(n, ec->f->deep), + qrPower_deep(n, n, ec->f->deep), + ecHasOrderA_deep(n, ec->d, ec->deep, n)), + SIZE_MAX, + &hash_state, &seed, &B, &b, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - // раскладка состояния - hash_state = objEnd(ec, octet); - seed = hash_state + beltHash_keep(); - B = (word*)seed; - stack = B + W_OF_B(512); // belt-hash(p..) beltHashStart(hash_state); beltHashStepH(params->p, no, hash_state); @@ -325,27 +355,27 @@ err_t bignParamsVal(const bign_params* params) bignSeedInc(seed); beltHashStepH(seed, 8, stack); // B <- belt-hash(p || a || seed) || belt-hash(p || a || seed + 1) - beltHashStepG((octet*)B, hash_state); - beltHashStepG((octet*)B + 32, stack); - wwFrom(B, B, 64); - // B <- B \mod p - zzMod(B, B, W_OF_O(64), ec->f->mod, n, stack); - wwTo(B, 64, B); + beltHashStepG(B, hash_state); + beltHashStepG(B + 32, stack); + // b <- B \mod p + wwFrom(b, B, 64); + zzMod(b, b, W_OF_O(64), ec->f->mod, n, stack); + wwTo(B, 64, b); // проверить условия алгоритма 6.1.4 - if (qrFrom(B, (octet*)B, ec->f, stack) && - wwEq(B, ec->B, n) && + if (qrFrom(b, B, ec->f, stack) && + wwEq(b, ec->B, n) && !wwIsZero(ec->B, n) && ecpIsValid(ec, stack) && - ecpIsSafeGroup(ec, 50, stack) && + ecpGroupIsSafe(ec, 50, stack) && zzJacobi(ec->B, n, ec->f->mod, n, stack) == 1) { - // B <- b^{(p + 1) / 4} = \sqrt{b} mod p - wwCopy(B, ec->f->mod, n); - zzAddW2(B, n, 1); - wwShLo(B, n, 2); - qrPower(B, ec->B, B, n, ec->f, stack); + // b <- b^{(p + 1) / 4} = \sqrt{b} mod p + wwCopy(b, ec->f->mod, n); + zzAddW2(b, n, 1); + wwShLo(b, n, 2); + qrPower(b, ec->B, b, n, ec->f, stack); // оставшиеся условия - if (!wwEq(B, ecY(ec->base, n), n) || + if (!wwEq(b, ecY(ec->base, n), n) || !ecHasOrderA(ec->base, ec, ec->order, n, stack)) code = ERR_BAD_PARAMS; } @@ -356,6 +386,19 @@ err_t bignParamsVal(const bign_params* params) return code; } +err_t bignParamsVal(const bign_params* params) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignParamsValEc(ec, params); + bignEcClose(ec); + return code; +} + /* ******************************************************************************* Генерация параметров @@ -365,10 +408,13 @@ err_t bignParamsVal(const bign_params* params) static bool_t ecpDetIsZero(const word a[], const word b[], const word p[], size_t n, void* stack) { - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; + word* t2; + // разметить память + memSlice(stack, + O_OF_W(2 * n), SIZE_0, SIZE_MAX, + &t1, &stack); + t2 = t1 + n; // t1 <- 4 A^3 zzSqrMod(t1, a, p, n, stack); zzMulMod(t1, t1, a, p, n, stack); @@ -384,21 +430,25 @@ static bool_t ecpDetIsZero(const word a[], const word b[], const word p[], static size_t ecpDetIsZero_deep(size_t n) { - return O_OF_W(2 * n) + + return memSliceSize(0, + O_OF_W(2 * n), utilMax(3, zzSqrMod_deep(n), zzMulMod_deep(n), - zzMulWMod_deep(n) - ); + zzMulWMod_deep(n)), + SIZE_MAX); } static bool_t ecpMOVIsMet(const word q[], const word p[], size_t n, size_t threshold, void* stack) { - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; + word* t2; + // разметить память + memSlice(stack, + O_OF_W(2 * n), SIZE_0, SIZE_MAX, + &t1, &stack); + t2 = t1 + n; // t1, t2 <- p mod q ASSERT(threshold > 0); zzMod(t1, p, n, q, n, stack); @@ -418,23 +468,12 @@ static bool_t ecpMOVIsMet(const word q[], const word p[], size_t n, static size_t ecpMOVIsMet_deep(size_t n) { - return O_OF_W(2 * n) + + return memSliceSize( + O_OF_W(2 * n), utilMax(2, zzMod_deep(n, n), - zzMulMod_deep(n) - ); -} - -static size_t bignParamsGen_deep(size_t n) -{ - return O_OF_W(4 * n) + 8 + beltHash_keep() + - utilMax(5, - beltHash_keep(), - priIsPrime_deep(n), - ecpDetIsZero_deep(n), - ecpMOVIsMet_deep(n), - zzPowerMod_deep(n, n) - ); + zzMulMod_deep(n)), + SIZE_MAX); } err_t bignParamsGen(bign_params* params, bign_pgen_calc_q calc_q, @@ -442,18 +481,18 @@ err_t bignParamsGen(bign_params* params, bign_pgen_calc_q calc_q, { err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* st; word* p; /* [n] */ word* a; /* [n] */ - word* b; /* [W_OF_B(512)] B / [n] b */ + octet* B; /* [64] */ + word* b; /* [W_OF_O(64)] (|B) */ word* q; /* [n] */ - word* yG; /* [n] */ + word* yG; /* [n] (|q) */ octet* seed; /* [8] */ octet* hash_state; /* [beltHash_keep] */ void* stack; // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || + if (!memIsValid(params, sizeof(bign_params)) || !calc_q) return ERR_BAD_INPUT; // проверить уровень стойкости @@ -474,18 +513,25 @@ err_t bignParamsGen(bign_params* params, bign_pgen_calc_q calc_q, !memIsZero(params->a + no, sizeof(params->a) - no)) return ERR_BAD_PARAMS; // создать состояние - st = blobCreate(bignParamsGen_deep(n)); + st = blobCreate2( + O_OF_W(n), + O_OF_W(n), + (size_t)64, + W_OF_O(64) | SIZE_HI, + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + (size_t)8, + beltHash_keep(), + utilMax(5, + beltHash_keep(), + priIsPrime_deep(n), + ecpDetIsZero_deep(n), + ecpMOVIsMet_deep(n), + zzPowerMod_deep(n, n)), + SIZE_MAX, + &p, &a, &B, &b, &q, &yG, &seed, &hash_state, &stack); if (st == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - p = (word*)st; - a = p + n; - b = a + n; - q = yG = b + n; - seed = (octet*)(q + n); - hash_state = seed + 8; - stack = hash_state + beltHash_keep(); - ASSERT((octet*)b + 64 <= seed); // загрузить и проверить p wwFrom(p, params->p, no); ASSERT(wwBitSize(p, n) == params->l * 2); @@ -522,10 +568,10 @@ err_t bignParamsGen(bign_params* params, bign_pgen_calc_q calc_q, bignSeedInc(seed); beltHashStepH(seed, 8, stack); // B <- belt-hash(p || a || seed) || belt-hash(p || a || seed + 1) - beltHashStepG((octet*)b, hash_state); - beltHashStepG((octet*)b + 32, stack); + beltHashStepG(B, hash_state); + beltHashStepG(B + 32, stack); // b <- B \mod p - wwFrom(b, b, 64); + wwFrom(b, B, 64); zzMod(b, b, W_OF_O(64), p, n, stack); // проверить b if (ecpDetIsZero(a, b, p, n, stack) || @@ -684,13 +730,13 @@ static size_t bignParamsDec_internal(bign_params* params, const octet der[], err_t bignParamsEnc(octet der[], size_t* count, const bign_params* params) { + err_t code; size_t len; - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(count, O_PER_S) || + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(count, O_PER_S) || !memIsNullOrValid(der, *count)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; len = bignParamsEnc_internal(0, params); if (len == SIZE_MAX) return ERR_BAD_PARAMS; diff --git a/src/crypto/bign/bign_sign.c b/src/crypto/bign/bign_sign.c index 194d54f9..f465072c 100644 --- a/src/crypto/bign/bign_sign.c +++ b/src/crypto/bign/bign_sign.c @@ -4,7 +4,7 @@ \brief STB 34.101.45 (bign): digital signature \project bee2 [cryptographic library] \created 2012.04.27 -\version 2025.05.07 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -30,70 +30,48 @@ ******************************************************************************* */ -static size_t bignSign_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n) + - utilMax(4, - beltHash_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n)); -} - -err_t bignSign(octet sig[], const bign_params* params, const octet oid_der[], +err_t bignSignEc(octet sig[], const ec_o* ec, const octet oid_der[], size_t oid_len, const octet hash[], const octet privkey[], gen_i rng, void* rng_state) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* R; /* [2n] точка R */ + word* k; /* [n] одноразовый личный ключ (|d) */ + word* R; /* [2 * n] точка R */ word* s0; /* [n/2] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(hash, no) || !memIsValid(privkey, no) || + !memIsValid(sig, no + no / 2) || + !memIsDisjoint2(hash, no, sig, no + no / 2)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить rng if (rng == 0) return ERR_BAD_RNG; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignSign_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(n / 2), + utilMax(4, + beltHash_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n)), + SIZE_MAX, + &d, &s1, &k, &R, &s0, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(hash, no) || - !memIsValid(privkey, no) || - !memIsValid(sig, no + no / 2) || - !memIsDisjoint2(hash, no, sig, no + no / 2)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = s1 = objEnd(ec, word); - k = d + n; - R = k + n; - s0 = R + n + n / 2; - stack = (octet*)(R + 2 * n); // загрузить d wwFrom(d, privkey, no); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -132,79 +110,80 @@ err_t bignSign(octet sig[], const bign_params* params, const octet oid_der[], zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(sig + no / 2, no, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } -static size_t bignSign2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bignSign(octet sig[], const bign_params* params, const octet oid_der[], + size_t oid_len, const octet hash[], const octet privkey[], gen_i rng, + void* rng_state) { - return O_OF_W(4 * n) + beltHash_keep() + - utilMax(6, - beltHash_keep(), - 32, - beltWBL_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(n / 2, n), - zzMod_deep(n + n / 2 + 1, n)); + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignSignEc(sig, ec, oid_der, oid_len, hash, privkey, rng, + rng_state); + bignEcClose(ec); + return code; } -err_t bignSign2(octet sig[], const bign_params* params, const octet oid_der[], +/* +******************************************************************************* +Детерминированная выработка ЭЦП +******************************************************************************* +*/ + +err_t bignSign2Ec(octet sig[], const ec_o* ec, const octet oid_der[], size_t oid_len, const octet hash[], const octet privkey[], const void* t, size_t t_len) { - err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* R; /* [2n] точка R */ + word* k; /* [n] одноразовый личный ключ (|d) */ + word* R; /* [2 * n] точка R */ word* s0; /* [n/2] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ octet* hash_state; /* [beltHash_keep] состояние хэширования */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(hash, no) || !memIsValid(privkey, no) || + !memIsValid(sig, no + no / 2) || + !memIsDisjoint2(hash, no, sig, no + no / 2)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить t if (!memIsNullOrValid(t, t_len)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignSign2_deep)); + ASSERT(n % 2 == 0); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(n / 2), + beltHash_keep(), + utilMax(6, + beltHash_keep(), + (size_t)32, + beltWBL_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(n / 2, n), + zzMod_deep(n + n / 2 + 1, n)), + SIZE_MAX, + &d, &s1, &k, &R, &s0, &hash_state, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(hash, no) || - !memIsValid(privkey, no) || - !memIsValid(sig, no + no / 2) || - !memIsDisjoint2(hash, no, sig, no + no / 2)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = s1 = objEnd(ec, word); - k = d + n; - R = k + n; - s0 = R + n + n / 2; - hash_state = (octet*)(R + 2 * n); - stack = hash_state + beltHash_keep(); // загрузить d wwFrom(d, privkey, no); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -260,73 +239,69 @@ err_t bignSign2(octet sig[], const bign_params* params, const octet oid_der[], zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(sig + no / 2, no, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } +err_t bignSign2(octet sig[], const bign_params* params, const octet oid_der[], + size_t oid_len, const octet hash[], const octet privkey[], const void* t, + size_t t_len) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignSign2Ec(sig, ec, oid_der, oid_len, hash, privkey, t, t_len); + bignEcClose(ec); + return code; +} + /* ******************************************************************************* Проверка ЭЦП ******************************************************************************* */ -static size_t bignVerify_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n) + - utilMax(2, - beltHash_keep(), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)); -} - -err_t bignVerify(const bign_params* params, const octet oid_der[], - size_t oid_len, const octet hash[], const octet sig[], const octet pubkey[]) +err_t bignVerifyEc(const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet hash[], const octet sig[], const octet pubkey[]) { err_t code; size_t no, n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* Q; /* [2n] открытый ключ */ - word* R; /* [2n] точка R */ + word* Q; /* [2 * n] открытый ключ */ + word* R; /* [2 * n] точка R (|Q) */ word* H; /* [n] хэш-значение */ - word* s0; /* [n / 2 + 1] первая часть подписи */ + word* s0; /* [n / 2 + 1] первая часть подписи (|H) */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + no = ec->f->no, n = ec->f->n; + ASSERT(n % 2 == 0); + // входной контроль + if (!memIsValid(hash, no) || !memIsValid(sig, no + no / 2) || + !memIsValid(pubkey, 2 * no)) return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; // создать состояние - state = blobCreate(bignStart_keep(params->l, bignVerify_deep)); + state = blobCreate2( + O_OF_W(2 * n), + O_OF_W(2 * n) | SIZE_HI, + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + utilMax(2, + beltHash_keep(), + ecAddMulA_deep(n, ec->d, ec->deep, 2, n, n / 2 + 1)), + SIZE_MAX, + &Q, &R, &H, &s0, &s1, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bignStart(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - no = ec->f->no; - n = ec->f->n; - ASSERT(n % 2 == 0); - // проверить входные указатели - if (!memIsValid(hash, no) || - !memIsValid(sig, no + no / 2) || - !memIsValid(pubkey, 2 * no)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - Q = R = objEnd(ec, word); - H = s0 = Q + 2 * n; - s1 = H + n; - stack = (octet*)(s1 + n); // загрузить Q if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || !qrFrom(ecY(Q, n), pubkey + no, ec->f, stack)) @@ -370,3 +345,17 @@ err_t bignVerify(const bign_params* params, const octet oid_der[], blobClose(state); return code; } + +err_t bignVerify(const bign_params* params, const octet oid_der[], + size_t oid_len, const octet hash[], const octet sig[], const octet pubkey[]) +{ + err_t code; + ec_o* ec; + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignVerifyEc(ec, oid_der, oid_len, hash, sig, pubkey); + bignEcClose(ec); + return code; +} diff --git a/src/crypto/bign96.c b/src/crypto/bign96.c index eab86e61..a639e4b0 100644 --- a/src/crypto/bign96.c +++ b/src/crypto/bign96.c @@ -1,10 +1,10 @@ /* ******************************************************************************* \file bign96.c -\brief Experimental Bign level 96 signatures +\brief Experimental Bign signatures of security level 96 \project bee2 [cryptographic library] \created 2021.01.20 -\version 2025.05.07 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -24,6 +24,7 @@ #include "bee2/math/ecp.h" #include "bee2/math/ww.h" #include "bee2/math/zz.h" +#include "bign/bign_lcl.h" /* ******************************************************************************* @@ -82,7 +83,10 @@ belt-32block static void belt32BlockEncr(octet block[24], const u32 key[8], u32* round) { - u32* t = (u32*)block; + u32* t; + // подготовить память + ASSERT(memIsAligned(block, 4)); + t = (u32*)block; u32From(t, block, 24); // round #1 beltBlockEncr3(t + 2, t + 3, t + 4, t + 5, key); @@ -109,6 +113,7 @@ err_t bign96ParamsStd(bign_params* params, const char* name) return ERR_BAD_INPUT; if (strEq(name, _curve96v1_name)) { + memSetZero(params, sizeof(bign_params)); params->l = 96; memCopy(params->p, _curve96v1_p, 24); memCopy(params->a, _curve96v1_a, 24); @@ -123,180 +128,34 @@ err_t bign96ParamsStd(bign_params* params, const char* name) /* ******************************************************************************* -Создание / закрытие эллиптической кривой +Предварительная проверка параметров ******************************************************************************* */ -typedef size_t(*bign96_deep_i)( - size_t n, /*!< [in] число слов для хранения элемента поля */ - size_t f_deep, /*!< [in] глубина стека базового поля */ - size_t ec_d, /*!< [in] число проективных координат */ - size_t ec_deep /*!< [in] глубина стека эллиптической кривой */ -); - -static size_t bign96Start_keep(bign96_deep_i deep) -{ - // размерности - size_t n = W_OF_B(192); - size_t f_keep = gfpCreate_keep(24); - size_t f_deep = gfpCreate_deep(24); - size_t ec_d = 3; - size_t ec_keep = ecpCreateJ_keep(n); - size_t ec_deep = ecpCreateJ_deep(n, f_deep); - // расчет - return f_keep + ec_keep + - utilMax(3, - ec_deep, - ecCreateGroup_deep(f_deep), - deep ? deep(n, f_deep, ec_d, ec_deep) : 0); -} - -static err_t bign96Start(void* state, const bign_params* params) +static err_t bign96ParamsCheck(const bign_params* params) { - // размерности - size_t n; - size_t f_keep; - size_t ec_keep; - // состояние - qr_o* f; /* поле */ - ec_o* ec; /* кривая */ - void* stack; /* вложенный стек */ - // pre - ASSERT(memIsValid(params, sizeof(bign_params))); - ASSERT(params->l == 96); - ASSERT(memIsValid(state, bign96Start_keep(0))); - // определить размерности - n = W_OF_B(192); - f_keep = gfpCreate_keep(24); - ec_keep = ecpCreateJ_keep(n); - // создать поле и выполнить минимальные проверки p - f = (qr_o*)((octet*)state + ec_keep); - stack = (octet*)f + f_keep; - if (!gfpCreate(f, params->p, 24, stack) || - wwBitSize(f->mod, n) != 192 || - wwGetBits(f->mod, 0, 2) != 3) - return ERR_BAD_PARAMS; - // создать кривую и группу, выполнить минимальную проверку order - ec = (ec_o*)state; - if (!ecpCreateJ(ec, f, params->a, params->b, stack) || - !ecCreateGroup(ec, 0, params->yG, params->q, 24, 1, stack) || - wwBitSize(ec->order, n) != params->l * 2 || - zzIsEven(ec->order, n)) - return ERR_BAD_PARAMS; - // присоединить f к ec - objAppend(ec, f, 0); - // все нормально - return ERR_OK; + err_t code; + code = bignParamsCheck2(params); + ERR_CALL_CHECK(code); + return (params->l == 96) ? ERR_OK : ERR_BAD_PARAMS; } /* ******************************************************************************* Проверка параметров - --# l = 96 (bign96ParamsVal) --# 2^{l - 1} < p, q < 2^l (bign96Start) --# p -- простое (ecpIsValid) --# q -- простое (ecpIsSafeGroup) --# p \equiv 3 \mod 4 (bign96Start) --# q != p (ecpIsSafeGroup) --# p^m \not\equiv 1 (mod q), m = 1, 2,..., 50 (ecpIsSafeGroup) --# a, b < p (ecpCreateJ in bign96Start) --# 0 != b (bign96ParamsVal) --# b \equiv B (mod p) (bign96ParamsVal) --# 4a^3 + 27b^2 \not\equiv 0 (\mod p) (ecpIsValid) --# (b / p) = 1 (zzJacobi) --# G = (0, b^{(p + 1) /4}) (bign96ParamsVal) --# qG = O (ecpHasOrder) ******************************************************************************* */ -static size_t bign96ParamsVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return beltHash_keep() + O_OF_B(512) + - utilMax(6, - beltHash_keep(), - ecpIsValid_deep(n, f_deep), - ecpIsSafeGroup_deep(n), - ecpIsOnA_deep(n, f_deep), - qrPower_deep(n, n, f_deep), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); -} - err_t bign96ParamsVal(const bign_params* params) { err_t code; - size_t n; - // состояние (буферы могут пересекаться) - void* state; - ec_o* ec; /* описание эллиптической кривой */ - octet* hash_state; /* [beltHash_keep] состояние хэширования */ - octet* hash_data; /* [8] данные хэширования */ - word* B; /* [W_OF_B(512)] переменная B */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // создать состояние - state = blobCreate(bign96Start_keep(bign96ParamsVal_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // раскладка состояния - hash_state = objEnd(ec, octet); - hash_data = hash_state + beltHash_keep(); - B = (word*)hash_data; - stack = hash_data + O_OF_B(512); - // belt-hash(p..) - beltHashStart(hash_state); - beltHashStepH(params->p, 24, hash_state); - // belt-hash(..a..) - beltHashStepH(params->a, 24, hash_state); - memCopy(stack, hash_state, beltHash_keep()); - // belt-hash(..seed) - memCopy(hash_data, params->seed, 8); - beltHashStepH(hash_data, 8, hash_state); - // belt-hash(..seed + 1) - wwFrom(B, hash_data, 8); - zzAddW2(B, W_OF_O(8), 1); - wwTo(hash_data, 8, B); - beltHashStepH(hash_data, 8, stack); - // B <- belt-hash(p || a || seed) || belt-hash(p || a || seed + 1) - beltHashStepG(hash_data, hash_state); - beltHashStepG(hash_data + 32, stack); - wwFrom(B, hash_data, 64); - // B <- B \mod p - zzMod(B, B, W_OF_O(64), ec->f->mod, n, stack); - wwTo(B, 64, B); - // проверить условия алгоритма 6.1.4 - if (qrFrom(B, (octet*)B, ec->f, stack) && - wwEq(B, ec->B, n) && - !wwIsZero(ec->B, n) && - ecpIsValid(ec, stack) && - ecpIsSafeGroup(ec, 50, stack) && - zzJacobi(ec->B, n, ec->f->mod, n, stack) == 1) - { - // B <- b^{(p + 1) / 4} = \sqrt{b} mod p - wwCopy(B, ec->f->mod, n); - zzAddW2(B, n, 1); - wwShLo(B, n, 2); - qrPower(B, ec->B, B, n, ec->f, stack); - // оставшиеся условия - if (!wwEq(B, ecY(ec->base, n), n) || - !ecHasOrderA(ec->base, ec, ec->order, n, stack)) - code = ERR_BAD_PARAMS; - } - else - code = ERR_BAD_PARAMS; - // завершение - blobClose(state); + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignParamsValEc(ec, params); + bignEcClose(ec); return code; } @@ -306,255 +165,58 @@ err_t bign96ParamsVal(const bign_params* params) ******************************************************************************* */ -static size_t bign96KeypairGen_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - err_t bign96KeypairGen(octet privkey[24], octet pubkey[48], const bign_params* params, gen_i rng, void* rng_state) { err_t code; - size_t n; - // состояние - void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ - void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // создать состояние - state = blobCreate(bign96Start_keep(bign96KeypairGen_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, 24) || !memIsValid(pubkey, 48)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; - // d <-R {1,2,..., q - 1} - if (!zzRandNZMod(d, ec->f->mod, n, rng, rng_state)) - { - blobClose(state); - return ERR_BAD_RNG; - } - // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) - { - // выгрузить ключи - wwTo(privkey, 24, d); - qrTo(pubkey, ecX(Q), ec->f, stack); - qrTo(pubkey + 24, ecY(Q, n), ec->f, stack); - } - else - code = ERR_BAD_PARAMS; - // завершение - blobClose(state); + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeypairGenEc(privkey, pubkey, ec, rng, rng_state); + bignEcClose(ec); return code; } -static size_t bign96KeypairVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - err_t bign96KeypairVal(const bign_params* params, const octet privkey[24], const octet pubkey[48]) { err_t code; - size_t n; - // состояние - void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ - void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // создать состояние - state = blobCreate(bign96Start_keep(bign96KeypairVal_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, 24) || !memIsValid(pubkey, 48)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; - // d <- privkey - wwFrom(d, privkey, 24); - // 0 < d < q? - wwFrom(Q, params->q, 24); - if (wwIsZero(d, n) || wwCmp(d, Q, n) >= 0) - { - blobClose(state); - return ERR_BAD_PRIVKEY; - } - // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) - { - // Q == pubkey? - wwTo(Q, 48, Q); - if (!memEq(Q, pubkey, 48)) - code = ERR_BAD_PUBKEY; - } - else - code = ERR_BAD_PARAMS; - // завершение - blobClose(state); + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignKeypairValEc(ec, privkey, pubkey); + bignEcClose(ec); return code; } -static size_t bign96PubkeyVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(2 * n) + - ecpIsOnA_deep(n, f_deep); -} - err_t bign96PubkeyVal(const bign_params* params, const octet pubkey[48]) { err_t code; - size_t n; - // состояние - void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* Q; /* [2n] открытый ключ */ - void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // создать состояние - state = blobCreate(bign96Start_keep(bign96PubkeyVal_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(pubkey, 48)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - Q = objEnd(ec, word); - stack = Q + 2 * n; - // загрузить pt - if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || - !qrFrom(ecY(Q, n), pubkey + 24, ec->f, stack)) - { - blobClose(state); - return ERR_BAD_PUBKEY; - } - // Q \in ec? - code = ecpIsOnA(Q, ec, stack) ? ERR_OK : ERR_BAD_PUBKEY; - // завершение - blobClose(state); + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignPubkeyValEc(ec, pubkey); + bignEcClose(ec); return code; } -static size_t bign96PubkeyCalc_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(n + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - err_t bign96PubkeyCalc(octet pubkey[48], const bign_params* params, const octet privkey[24]) { err_t code; - size_t n; - // состояние - void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* d; /* [n] личный ключ */ - word* Q; /* [2n] открытый ключ */ - void* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) - return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // создать состояние - state = blobCreate(bign96Start_keep(bign96PubkeyCalc_deep)); - if (state == 0) - return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(privkey, 24) || !memIsValid(pubkey, 48)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + n; - stack = Q + 2 * n; - // загрузить d - wwFrom(d, privkey, 24); - if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) - { - blobClose(state); - return ERR_BAD_PRIVKEY; - } - // Q <- d G - if (ecMulA(Q, ec->base, ec, d, n, stack)) - { - // выгрузить открытый ключ - qrTo(pubkey, ecX(Q), ec->f, stack); - qrTo(pubkey + 24, ecY(Q, n), ec->f, stack); - } - else - code = ERR_BAD_PARAMS; - // завершение - blobClose(state); + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bignPubkeyCalcEc(pubkey, ec, privkey); + bignEcClose(ec); return code; } @@ -564,68 +226,46 @@ err_t bign96PubkeyCalc(octet pubkey[48], const bign_params* params, ******************************************************************************* */ -static size_t bign96Sign_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bign96SignEc(octet sig[34], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet hash[24], const octet privkey[24], gen_i rng, + void* rng_state) { - return O_OF_W(3 * n + 2 * W_OF_O(13)) + - utilMax(4, - beltHash_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(W_OF_O(13), n), - zzMod_deep(n + W_OF_O(13), n)); -} - -err_t bign96Sign(octet sig[34], const bign_params* params, - const octet oid_der[], size_t oid_len, const octet hash[24], - const octet privkey[24], gen_i rng, void* rng_state) -{ - err_t code; size_t n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* R; /* [2n] точка R */ + word* k; /* [n] одноразовый личный ключ (|d) */ + word* R; /* [2 * n] точка R */ word* s0; /* [W_OF_O(13)] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + n = ec->f->n; + // входной контроль + if (!memIsValid(hash, 24) || !memIsValid(privkey, 24) || + !memIsValid(sig, 34) || !memIsDisjoint2(hash, 24, sig, 34)) return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить rng if (rng == 0) return ERR_BAD_RNG; // создать состояние - state = blobCreate(bign96Start_keep(bign96Sign_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(W_OF_O(13)), + utilMax(4, + beltHash_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(W_OF_O(13), n), + zzMod_deep(n + W_OF_O(13), n)), + SIZE_MAX, + &d, &s1, &k, &R, &s0, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(hash, 24) || - !memIsValid(privkey, 24) || - !memIsValid(sig, 34) || - !memIsDisjoint2(hash, 24, sig, 34)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = s1 = objEnd(ec, word); - k = d + n; - R = k + n; - s0 = R + n + W_OF_O(13); - stack = (octet*)(s0 + W_OF_O(13)); // загрузить d wwFrom(d, privkey, 24); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -664,79 +304,78 @@ err_t bign96Sign(octet sig[34], const bign_params* params, zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(sig + 10, 24, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } -static size_t bign96Sign2_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t bign96Sign(octet sig[34], const bign_params* params, + const octet oid_der[], size_t oid_len, const octet hash[24], + const octet privkey[24], gen_i rng, void* rng_state) { - return O_OF_W(3 * n + 2 * W_OF_O(13)) + - beltHash_keep() + - utilMax(6, - beltHash_keep(), - 32, - beltKWP_keep(), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMul_deep(W_OF_O(13), n), - zzMod_deep(n + W_OF_O(13), n)); + err_t code; + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bign96SignEc(sig, ec, oid_der, oid_len, hash, privkey, rng, + rng_state); + bignEcClose(ec); + return code; } -err_t bign96Sign2(octet sig[34], const bign_params* params, - const octet oid_der[], size_t oid_len, const octet hash[24], - const octet privkey[24], const void* t, size_t t_len) +/* +******************************************************************************* +Детерминированная выработка ЭЦП +******************************************************************************* +*/ + +err_t bign96Sign2Ec(octet sig[34], const ec_o* ec, const octet oid_der[], + size_t oid_len, const octet hash[24], const octet privkey[24], + const void* t, size_t t_len) { - err_t code; size_t n; - u32 round = 1; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ word* d; /* [n] личный ключ */ - word* k; /* [n] одноразовый личный ключ */ - word* R; /* [2n] точка R */ + word* k; /* [n] одноразовый личный ключ (|d) */ + word* R; /* [2 * n] точка R */ word* s0; /* [W_OF_O(13)] первая часть подписи */ word* s1; /* [n] вторая часть подписи */ - octet* hash_state; /* [beltHash_keep] состояние хэширования */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + octet* hash_state; /* [beltHash_keep()] состояние хэширования */ + void* stack; + u32 round = 1; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + n = ec->f->n; + // входной контроль + if (!memIsValid(hash, 24) || !memIsValid(privkey, 24) || + !memIsValid(sig, 34) || !memIsDisjoint2(hash, 24, sig, 34)) return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // проверить oid_der if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; - // проверить t if (!memIsNullOrValid(t, t_len)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate(bign96Start_keep(bign96Sign2_deep)); + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(n), + O_OF_W(2 * n), + O_OF_W(W_OF_O(13)), + beltHash_keep(), + utilMax(6, + beltHash_keep(), + (size_t)32, + beltKWP_keep(), + ecMulA_deep(n, ec->d, ec->deep, n), + zzMul_deep(W_OF_O(13), n), + zzMod_deep(n + W_OF_O(13), n)), + SIZE_MAX, + &d, &s1, &k, &R, &s0, &hash_state, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(hash, 24) || - !memIsValid(privkey, 24) || - !memIsValid(sig, 34) || - !memIsDisjoint2(hash, 24, sig, 34)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - d = s1 = objEnd(ec, word); - k = d + n; - R = k + n; - s0 = R + n + W_OF_O(13); - hash_state = (octet*)(s0 + W_OF_O(13)); - stack = hash_state + beltHash_keep(); // загрузить d wwFrom(d, privkey, 24); if (wwIsZero(d, n) || wwCmp(d, ec->order, n) >= 0) @@ -791,72 +430,68 @@ err_t bign96Sign2(octet sig[34], const bign_params* params, zzSubMod(s1, s1, k, ec->order, n); // выгрузить s1 wwTo(sig + 10, 24, s1); - // все нормально + // завершение blobClose(state); return ERR_OK; } +err_t bign96Sign2(octet sig[34], const bign_params* params, + const octet oid_der[], size_t oid_len, const octet hash[24], + const octet privkey[24], const void* t, size_t t_len) +{ + err_t code; + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bign96Sign2Ec(sig, ec, oid_der, oid_len, hash, privkey, t, t_len); + bignEcClose(ec); + return code; +} + /* ******************************************************************************* Проверка ЭЦП ******************************************************************************* */ -static size_t bign96Verify_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(4 * n) + - utilMax(2, - beltHash_keep(), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)); -} - -err_t bign96Verify(const bign_params* params, const octet oid_der[], - size_t oid_len, const octet hash[24], const octet sig[34], - const octet pubkey[48]) +err_t bign96VerifyEc(const ec_o* ec, const octet oid_der[], size_t oid_len, + const octet hash[24], const octet sig[34], const octet pubkey[48]) { err_t code; size_t n; - // состояние (буферы могут пересекаться) void* state; - ec_o* ec; /* описание эллиптической кривой */ - word* Q; /* [2n] открытый ключ */ - word* R; /* [2n] точка R */ + word* Q; /* [2 * n] открытый ключ */ + word* R; /* [2 * n] точка R (|Q) */ word* H; /* [n] хэш-значение */ - word* s0; /* [W_OF_O(13)] первая часть подписи */ + word* s0; /* [W_OF_O(13)] первая часть подписи (|H) */ word* s1; /* [n] вторая часть подписи */ - octet* stack; - // проверить params - if (!memIsValid(params, sizeof(bign_params))) + void* stack; + // pre + ASSERT(ecIsOperable(ec)); + // размерности + n = ec->f->n; + // входной контроль + if (!memIsValid(hash, 24) || !memIsValid(sig, 34) || + !memIsValid(pubkey, 48)) return ERR_BAD_INPUT; - if (params->l != 96) - return ERR_BAD_PARAMS; - // проверить oid_der - if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) + if (oid_len == SIZE_MAX || oidFromDER(0, oid_der, oid_len) == SIZE_MAX) return ERR_BAD_OID; // создать состояние - state = blobCreate(bign96Start_keep(bign96Verify_deep)); + state = blobCreate2( + O_OF_W(2 * n), + O_OF_W(2 * n) | SIZE_HI, + O_OF_W(n), + O_OF_W(W_OF_O(13)) | SIZE_HI, + O_OF_W(n), + utilMax(2, + beltHash_keep(), + ecAddMulA_deep(n, ec->d, ec->deep, 2, n, W_OF_O(13))), + SIZE_MAX, + &Q, &R, &H, &s0, &s1, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // старт - code = bign96Start(state, params); - ERR_CALL_HANDLE(code, blobClose(state)); - ec = (ec_o*)state; - // размерности - n = ec->f->n; - // проверить входные указатели - if (!memIsValid(hash, 24) || - !memIsValid(sig, 34) || - !memIsValid(pubkey, 48)) - { - blobClose(state); - return ERR_BAD_INPUT; - } - // раскладка состояния - Q = R = objEnd(ec, word); - H = s0 = Q + 2 * n; - s1 = H + n; - stack = (octet*)(s1 + n); // загрузить Q if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || !qrFrom(ecY(Q, n), pubkey + 24, ec->f, stack)) @@ -885,7 +520,7 @@ err_t bign96Verify(const bign_params* params, const octet oid_der[], ((octet*)s0)[10] = ((octet*)s0)[11] = 0, ((octet*)s0)[12] = 0x80; wwFrom(s0, s0, 13); // R <- s1 G + (s0 + 2^l) Q - if (!ecAddMulA(R, ec, stack, 2, ec->base, s1, n, Q, s0, (size_t)W_OF_O(13))) + if (!ecAddMulA(R, ec, stack, 2, ec->base, s1, n, Q, s0, W_OF_O(13))) { blobClose(state); return ERR_BAD_SIG; @@ -901,3 +536,18 @@ err_t bign96Verify(const bign_params* params, const octet oid_der[], blobClose(state); return code; } + +err_t bign96Verify(const bign_params* params, const octet oid_der[], + size_t oid_len, const octet hash[24], const octet sig[34], + const octet pubkey[48]) +{ + err_t code; + ec_o* ec; + code = bign96ParamsCheck(params); + ERR_CALL_CHECK(code); + code = bignEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = bign96VerifyEc(ec, oid_der, oid_len, hash, sig, pubkey); + bignEcClose(ec); + return code; +} diff --git a/src/crypto/botp.c b/src/crypto/botp.c index 499daf4a..6cc616fe 100644 --- a/src/crypto/botp.c +++ b/src/crypto/botp.c @@ -4,7 +4,7 @@ \brief STB 34.101.47/botp: OTP algorithms \project bee2 [cryptographic library] \created 2015.11.02 -\version 2025.08.28 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -106,17 +106,18 @@ void botpCtrNext(octet ctr[8]) typedef struct { - size_t digit; /*< число цифр в пароле */ - octet ctr[8]; /*< счетчик */ - octet ctr1[8]; /*< копия счетчика */ - octet mac[32]; /*< имитовставка */ - char otp[10]; /*< текущий пароль */ - octet stack[]; /*< [2 * beltHMAC_deep()] */ + size_t digit; /*< число цифр в пароле */ + octet ctr[8]; /*< счетчик */ + octet ctr1[8]; /*< копия счетчика */ + octet mac[32]; /*< имитовставка */ + char otp[10]; /*< текущий пароль */ + mem_align_t stack[]; /*< 2 состояния beltHMAC */ } botp_hotp_st; size_t botpHOTP_keep() { - return sizeof(botp_hotp_st) + 2 * beltHMAC_keep(); + return sizeof(botp_hotp_st) + + memSliceSize(beltHMAC_keep(), beltHMAC_keep(), SIZE_MAX); } void botpHOTPStart(void* state, size_t digit, const octet key[], @@ -126,7 +127,7 @@ void botpHOTPStart(void* state, size_t digit, const octet key[], ASSERT(6 <= digit && digit <= 8); ASSERT(memIsDisjoint2(key, key_len, state, botpHOTP_keep())); st->digit = digit; - beltHMACStart(st->stack + beltHMAC_keep(), key, key_len); + beltHMACStart(memSliceNext(st->stack, beltHMAC_keep()), key, key_len); } void botpHOTPStepS(void* state, const octet ctr[8]) @@ -143,7 +144,8 @@ void botpHOTPStepR(char* otp, void* state) ASSERT(memIsDisjoint2(otp, st->digit + 1, state, botpHOTP_keep()) || otp == st->otp); // вычислить имитовставку - memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep()); + memCopy(st->stack, memSliceNext2(st->stack, beltHMAC_keep()), + beltHMAC_keep()); beltHMACStepA(st->ctr, 8, st->stack); beltHMACStepG(st->mac, st->stack); // построить пароль @@ -231,16 +233,17 @@ err_t botpHOTPVerify(const char* otp, const octet key[], size_t key_len, typedef struct { - size_t digit; /*< число цифр в пароле */ - octet t[8]; /*< округленная отметка времени */ - octet mac[32]; /*< имитовставка */ - char otp[10]; /*< текущий пароль */ - octet stack[]; /*< [2 * beltHMAC_deep()] */ + size_t digit; /*< число цифр в пароле */ + octet t[8]; /*< округленная отметка времени */ + octet mac[32]; /*< имитовставка */ + char otp[10]; /*< текущий пароль */ + mem_align_t stack[]; /*< 2 состояния beltHMAC */ } botp_totp_st; size_t botpTOTP_keep() { - return sizeof(botp_totp_st) + 2 * beltHMAC_keep(); + return sizeof(botp_totp_st) + + memSliceSize( beltHMAC_keep(), beltHMAC_keep(), SIZE_MAX); } void botpTOTPStart(void* state, size_t digit, const octet key[], @@ -250,7 +253,7 @@ void botpTOTPStart(void* state, size_t digit, const octet key[], ASSERT(6 <= digit && digit <= 8); ASSERT(memIsDisjoint2(key, key_len, state, botpTOTP_keep())); st->digit = digit; - beltHMACStart(st->stack + beltHMAC_keep(), key, key_len); + beltHMACStart(memSliceNext(st->stack, beltHMAC_keep()), key, key_len); } void botpTOTPStepR(char* otp, tm_time_t t, void* state) @@ -261,7 +264,8 @@ void botpTOTPStepR(char* otp, tm_time_t t, void* state) ASSERT(memIsDisjoint2(otp, st->digit + 1, state, botpHOTP_keep()) || otp == st->otp); // вычислить имитовставку - memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep()); + memCopy(st->stack, memSliceNext2(st->stack, beltHMAC_keep()), + beltHMAC_keep()); botpTimeToCtr(st->t, t); beltHMACStepA(st->t, 8, st->stack); beltHMACStepG(st->mac, st->stack); @@ -337,27 +341,28 @@ err_t botpTOTPVerify(const char* otp, const octet key[], size_t key_len, typedef struct botp_ocra_st { - size_t digit; /*< число цифр в пароле */ - octet ctr[8]; /*< счетчик */ - octet ctr1[8]; /*< копия счетчика */ - size_t ctr_len; /*< длина счетчика */ - octet q[128]; /*< запрос */ - char q_type; /*< тип запроса (A, N, H) */ - size_t q_max; /*< максимальная длина одиночного запроса */ - octet p[64]; /*< хэш-значение статического пароля */ - size_t p_len; /*< длина p */ - octet s[512]; /*< идентификатор сеанса */ - size_t s_len; /*< длина идентификатора */ - octet t[8]; /*< отметка времени */ - tm_time_t ts; /*< шаг времени */ - octet mac[32]; /*< имитовставка */ - char otp[10]; /*< текущий пароль */ - octet stack[]; /*< [2 * beltHMAC_deep()] */ + size_t digit; /*< число цифр в пароле */ + octet ctr[8]; /*< счетчик */ + octet ctr1[8]; /*< копия счетчика */ + size_t ctr_len; /*< длина счетчика */ + octet q[128]; /*< запрос */ + char q_type; /*< тип запроса (A, N, H) */ + size_t q_max; /*< максимальная длина одиночного запроса */ + octet p[64]; /*< хэш-значение статического пароля */ + size_t p_len; /*< длина p */ + octet s[512]; /*< идентификатор сеанса */ + size_t s_len; /*< длина идентификатора */ + octet t[8]; /*< отметка времени */ + tm_time_t ts; /*< шаг времени */ + octet mac[32]; /*< имитовставка */ + char otp[10]; /*< текущий пароль */ + mem_align_t stack[]; /*< 2 состояния beltHMAC */ } botp_ocra_st; size_t botpOCRA_keep() { - return sizeof(botp_ocra_st) + 2 * beltHMAC_keep(); + return sizeof(botp_ocra_st) + + memSliceSize( beltHMAC_keep(), beltHMAC_keep(), SIZE_MAX); } static const char ocra_prefix[] = "OCRA-1:HOTP-"; @@ -496,9 +501,9 @@ bool_t botpOCRAStart(void* state, const char* suite, const octet key[], if (*suite) return FALSE; // запуск HMAC - beltHMACStart(st->stack + beltHMAC_keep(), key, key_len); + beltHMACStart(memSliceNext(st->stack, beltHMAC_keep()), key, key_len); beltHMACStepA(suite_save, strLen(suite_save) + 1, - st->stack + beltHMAC_keep()); + memSliceNext(st->stack, beltHMAC_keep())); return TRUE; } @@ -539,7 +544,8 @@ void botpOCRAStepR(char* otp, const octet q[], size_t q_len, tm_time_t t, ASSERT(memIsDisjoint2(q, q_len, state, botpOCRA_keep() || q == st->q)); ASSERT(t != TIME_ERR); // вычислить имитовставку - memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep()); + memCopy(st->stack, memSliceNext2(st->stack, beltHMAC_keep()), + beltHMAC_keep()); if (st->ctr_len) beltHMACStepA(st->ctr, 8, st->stack), botpCtrNext(st->ctr); memMove(st->q, q, q_len); diff --git a/src/crypto/bpki.c b/src/crypto/bpki.c index ac965210..3faf23e1 100644 --- a/src/crypto/bpki.c +++ b/src/crypto/bpki.c @@ -4,7 +4,7 @@ \brief STB 34.101.78 (bpki): PKI helpers \project bee2 [cryptographic library] \created 2021.04.03 -\version 2025.05.12 +\version 2025.09.15 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -315,9 +315,11 @@ err_t bpkiPrivkeyWrap(octet epki[], size_t* epki_len, const octet privkey[], size_t privkey_len, const octet pwd[], size_t pwd_len, const octet salt[8], size_t iter) { - size_t pki_len, edata_len, count; - octet* key; err_t code; + size_t pki_len; + size_t edata_len; + size_t count; + octet* key; // проверить входные данные if (iter < 10000) return ERR_BAD_INPUT; @@ -373,12 +375,15 @@ err_t bpkiPrivkeyWrap(octet epki[], size_t* epki_len, const octet privkey[], err_t bpkiPrivkeyUnwrap(octet privkey[], size_t* privkey_len, const octet epki[], size_t epki_len, const octet pwd[], size_t pwd_len) { - size_t edata_len, pki_len, count, iter; - void* state; - octet* salt; - octet* key; - octet* edata; err_t code; + size_t edata_len; + size_t pki_len; + size_t count; + size_t iter; + void* state; + octet* salt; /* [8] */ + octet* key; /* [32] */ + octet* edata; /* [edata_len] */ // проверить входные данные if (epki_len == SIZE_MAX || !memIsValid(epki, epki_len) || !memIsValid(pwd, pwd_len) || @@ -389,12 +394,14 @@ err_t bpkiPrivkeyUnwrap(octet privkey[], size_t* privkey_len, if (count != epki_len) return ERR_BAD_FORMAT; // подготовить буферы для параметров PBKDF2 - state = blobCreate(8 + 32 + edata_len); - if (!state) + state = blobCreate2( + (size_t)8, + (size_t)32, + edata_len, + SIZE_MAX, + &salt, &key, &edata); + if (state == 0) return ERR_OUTOFMEMORY; - salt = (octet*)state; - key = salt + 8; - edata = key + 32; // выделить edata VERIFY(bpkiEdataDec(edata, 0, salt, &iter, epki, epki_len) == epki_len); // построить ключ защиты @@ -428,9 +435,11 @@ err_t bpkiShareWrap(octet epki[], size_t* epki_len, const octet share[], size_t share_len, const octet pwd[], size_t pwd_len, const octet salt[8], size_t iter) { - size_t pki_len, edata_len, count; - octet* key; err_t code; + size_t pki_len; + size_t edata_len; + size_t count; + octet* key; // проверить входные данные if (iter < 10000) return ERR_BAD_INPUT; @@ -486,12 +495,15 @@ err_t bpkiShareWrap(octet epki[], size_t* epki_len, const octet share[], err_t bpkiShareUnwrap(octet share[], size_t* share_len, const octet epki[], size_t epki_len, const octet pwd[], size_t pwd_len) { - size_t edata_len, pki_len, count, iter; - void* state; - octet* salt; - octet* key; - octet* edata; err_t code; + size_t edata_len; + size_t pki_len; + size_t count; + size_t iter; + void* state; + octet* salt; /* [8] */ + octet* key; /* [32] */ + octet* edata; /* [edata_len] */ // проверить входные данные if (epki_len == SIZE_MAX || !memIsValid(epki, epki_len) || !memIsValid(pwd, pwd_len) || @@ -502,12 +514,14 @@ err_t bpkiShareUnwrap(octet share[], size_t* share_len, if (count != epki_len) return ERR_BAD_FORMAT; // подготовить буферы для параметров PBKDF2 - state = blobCreate(8 + 32 + edata_len); - if (!state) + state = blobCreate2( + (size_t)8, + (size_t)32, + edata_len, + SIZE_MAX, + &salt, &key, &edata); + if (state == 0) return ERR_OUTOFMEMORY; - salt = (octet*)state; - key = salt + 8; - edata = key + 32; // выделить edata VERIFY(bpkiEdataDec(edata, 0, salt, &iter, epki, epki_len) == epki_len); // построить ключ защиты diff --git a/src/crypto/brng.c b/src/crypto/brng.c index 4d934619..1395eb4d 100644 --- a/src/crypto/brng.c +++ b/src/crypto/brng.c @@ -4,7 +4,7 @@ \brief STB 34.101.47 (brng): algorithms of pseudorandom number generation \project bee2 [cryptographic library] \created 2013.01.31 -\version 2025.06.11 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -20,63 +20,54 @@ /* ******************************************************************************* -Ускорители: быстрые операции над блоками brng +Операции над блоками ******************************************************************************* */ -static void brngBlockNeg(octet dest[32], const octet src[32]) -{ - register size_t i = W_OF_O(32); - while (i--) - ((word*)dest)[i] = ~((const word*)src)[i]; -} - -static void brngBlockXor2(octet dest[32], const octet src[32]) -{ - register size_t i = W_OF_O(32); - while (i--) - ((word*)dest)[i] ^= ((const word*)src)[i]; -} - static void brngBlockInc(octet block[32]) { - register size_t i = 0; - word* w = (word*)block; - do + enum {n = W_OF_O(32)}; + register word carry = 1; + size_t i; + word* b; + ASSERT(memIsAligned(block, O_PER_W)); + b = (word*)block; + for (i = 0; i < n - 1; ++i) { #if (OCTET_ORDER == BIG_ENDIAN) - w[i] = wordRev(w[i]); - ++w[i]; - w[i] = wordRev(w[i]); -#else - ++w[i]; + b[i] = wordRev(b[i]); +#endif + b[i] += carry, carry = wordLess(b[i], carry); +#if (OCTET_ORDER == BIG_ENDIAN) + b[i] = wordRev(b[i]); #endif } - while (w[i] == 0 && i++ < W_OF_O(32)); - CLEAN(i); + b[n - 1] += carry; + CLEAN(carry); } /* ******************************************************************************* Генерация в режиме CTR -В brng_ctr_st::state_ex размещаются два beltHash-состояния: +В brng_ctr_st::stack размещаются два состояния beltHash: - вспомогательное состояние; - состояние beltHash(key ||....). ******************************************************************************* */ typedef struct { - octet s[32]; /*< переменная s */ - octet r[32]; /*< переменная r */ - octet block[32]; /*< блок выходных данных */ - size_t reserved; /*< резерв выходных октетов */ - octet state_ex[]; /*< [2 beltHash_keep()] хэш-состояния */ + octet s[32]; /*< переменная s */ + octet r[32]; /*< переменная r */ + octet block[32]; /*< блок выходных данных */ + size_t reserved; /*< резерв выходных октетов */ + mem_align_t stack[]; /*< 2 состояния beltHash */ } brng_ctr_st; size_t brngCTR_keep() { - return sizeof(brng_ctr_st) + 2 * beltHash_keep(); + return sizeof(brng_ctr_st) + + memSliceSize(beltHash_keep(), beltHash_keep(), SIZE_MAX); } void brngCTRStart(void* state, const octet key[32], const octet iv[32]) @@ -85,15 +76,16 @@ void brngCTRStart(void* state, const octet key[32], const octet iv[32]) ASSERT(memIsDisjoint2(s, brngCTR_keep(), key, 32)); ASSERT(iv == 0 || memIsDisjoint2(s, brngCTR_keep(), iv, 32)); // обработать key - beltHashStart(s->state_ex + beltHash_keep()); - beltHashStepH(key, 32, s->state_ex + beltHash_keep()); + beltHashStart(memSliceNext(s->stack, beltHash_keep())); + beltHashStepH(key, 32, memSliceNext(s->stack, beltHash_keep())); // сохранить iv if (iv) memCopy(s->s, iv, 32); else memSetZero(s->s, 32); // r <- ~s - brngBlockNeg(s->r, s->s); + memCopy(s->r, s->s, 32); + memNeg(s->r, 32); // нет выходных данных s->reserved = 0; } @@ -120,14 +112,15 @@ void brngCTRStepR(void* buf, size_t count, void* state) while (count >= 32) { // Y_t <- belt-hash(key || s || X_t || r) - memCopy(s->state_ex, s->state_ex + beltHash_keep(), beltHash_keep()); - beltHashStepH(s->s, 32, s->state_ex); - beltHashStepH(buf, 32, s->state_ex); - beltHashStepH(s->r, 32, s->state_ex); - beltHashStepG(buf, s->state_ex); + memCopy(s->stack, memSliceNext2(s->stack, beltHash_keep()), + beltHash_keep()); + beltHashStepH(s->s, 32, s->stack); + beltHashStepH(buf, 32, s->stack); + beltHashStepH(s->r, 32, s->stack); + beltHashStepG(buf, s->stack); // next brngBlockInc(s->s); - brngBlockXor2(s->r, buf); + memXor2(s->r, buf, 32); buf = (octet*)buf + 32; count -= 32; } @@ -136,17 +129,18 @@ void brngCTRStepR(void* buf, size_t count, void* state) { // block <- beltHash(key || s || zero_pad(X_t) || r) memSetZero(s->block + count, 32 - count); - memCopy(s->state_ex, s->state_ex + beltHash_keep(), beltHash_keep()); - beltHashStepH(s->s, 32, s->state_ex); - beltHashStepH(buf, count, s->state_ex); - beltHashStepH(s->block + count, 32 - count, s->state_ex); - beltHashStepH(s->r, 32, s->state_ex); - beltHashStepG(s->block, s->state_ex); + memCopy(s->stack, memSliceNext2(s->stack, beltHash_keep()), + beltHash_keep()); + beltHashStepH(s->s, 32, s->stack); + beltHashStepH(buf, count, s->stack); + beltHashStepH(s->block + count, 32 - count, s->stack); + beltHashStepH(s->r, 32, s->stack); + beltHashStepG(s->block, s->stack); // Y_t <- left(block) memCopy(buf, s->block, count); // next brngBlockInc(s->s); - brngBlockXor2(s->r, s->block); + memXor2(s->r, s->block, 32); s->reserved = 32 - count; } } @@ -183,7 +177,7 @@ err_t brngCTRRand(void* buf, size_t count, const octet key[32], octet iv[32]) ******************************************************************************* Генерация в режиме HMAC -В brng_hmac_st::state_ex размещаются два beltHMAC-состояния: +В brng_hmac_st::stack размещаются два beltHMAC-состояния: - вспомогательное состояние; - состояние beltHMAC(key, ...). @@ -198,12 +192,13 @@ typedef struct octet r[32]; /*< переменная r */ octet block[32]; /*< блок выходных данных */ size_t reserved; /*< резерв выходных октетов */ - octet state_ex[]; /*< [2 * beltHMAC_keep()] hmac-состояния */ + mem_align_t stack[]; /*< 2 состояния beltHMAC */ } brng_hmac_st; size_t brngHMAC_keep() { - return sizeof(brng_hmac_st) + 2 * beltHMAC_keep(); + return sizeof(brng_hmac_st) + + memSliceSize(beltHMAC_keep(), beltHMAC_keep(), SIZE_MAX); } void brngHMACStart(void* state, const octet key[], size_t key_len, @@ -221,11 +216,12 @@ void brngHMACStart(void* state, const octet key[], size_t key_len, else s->iv = iv; // обработать key - beltHMACStart(s->state_ex + beltHMAC_keep(), key, key_len); + beltHMACStart(memSliceNext(s->stack, beltHMAC_keep()), key, key_len); // r <- beltHMAC(key, iv) - memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep()); - beltHMACStepA(iv, iv_len, s->state_ex); - beltHMACStepG(s->r, s->state_ex); + memCopy(s->stack, memSliceNext2(s->stack, beltHMAC_keep()), + beltHMAC_keep()); + beltHMACStepA(iv, iv_len, s->stack); + beltHMACStepG(s->r, s->stack); // нет выходных данных s->reserved = 0; } @@ -252,12 +248,13 @@ void brngHMACStepR(void* buf, size_t count, void* state) while (count >= 32) { // r <- beltHMAC(key, r) - memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep()); - beltHMACStepA(s->r, 32, s->state_ex); - beltHMACStepG(s->r, s->state_ex); + memCopy(s->stack, memSliceNext2(s->stack, beltHMAC_keep()), + beltHMAC_keep()); + beltHMACStepA(s->r, 32, s->stack); + beltHMACStepG(s->r, s->stack); // Y_t <- beltHMAC(key, r || iv) - beltHMACStepA(s->iv, s->iv_len, s->state_ex); - beltHMACStepG(buf, s->state_ex); + beltHMACStepA(s->iv, s->iv_len, s->stack); + beltHMACStepG(buf, s->stack); // next buf = (octet*)buf + 32; count -= 32; @@ -266,12 +263,13 @@ void brngHMACStepR(void* buf, size_t count, void* state) if (count) { // r <- beltHMAC(key, r) - memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep()); - beltHMACStepA(s->r, 32, s->state_ex); - beltHMACStepG(s->r, s->state_ex); + memCopy(s->stack, memSliceNext(s->stack, beltHMAC_keep()), + beltHMAC_keep()); + beltHMACStepA(s->r, 32, s->stack); + beltHMACStepG(s->r, s->stack); // Y_t <- left(beltHMAC(key, r || iv)) - beltHMACStepA(s->iv, s->iv_len, s->state_ex); - beltHMACStepG(s->block, s->state_ex); + beltHMACStepA(s->iv, s->iv_len, s->stack); + beltHMACStepG(s->block, s->stack); memCopy(buf, s->block, count); // next s->reserved = 32 - count; diff --git a/src/crypto/btok/btok_bauth.c b/src/crypto/btok/btok_bauth.c index 1b760c19..94fb1ad2 100644 --- a/src/crypto/btok/btok_bauth.c +++ b/src/crypto/btok/btok_bauth.c @@ -4,7 +4,7 @@ \brief STB 34.101.79 (btok): BAUTH protocol \project bee2 [cryptographic library] \created 2022.02.22 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -21,6 +21,7 @@ #include "bee2/math/ecp.h" #include "bee2/math/ww.h" #include "bee2/math/zz.h" +#include "crypto/bake/bake_lcl.h" #include "crypto/bign/bign_lcl.h" /* @@ -66,61 +67,72 @@ B=CT typedef struct { - obj_hdr_t hdr; /*< заголовок */ -// ptr_table { - ec_o* ec; /*< описание эллиптической кривой */ - word* d; /*< [ec->f->n] долговременный личный ключ */ - word* Vct; /*< [2*ec->f->n] Vct */ - octet* R; /*< [l/8] одноразовый секретный ключ */ -// } bign_params params[1]; /*< параметры */ bake_settings settings[1]; /*< настройки */ bake_cert cert[1]; /*< сертификат */ octet K0[32]; /*< ключ K0 */ octet K1[32]; /*< ключ K1 */ octet K2[32]; /*< ключ K2 */ - octet data[]; /*< данные */ -} bake_bauth_t_o; + ec_o* ec; /*< эллиптическая кривая */ + word* d; /*< [n] долговременный личный ключ */ + word* Vct; /*< [2 * n] Vct */ + octet* R; /*< [no / 2] одноразовый секретный ключ */ + void* stack; /*< [btokBAuthT_deep] стек */ + mem_align_t data[]; /*< данные */ +} btok_bauth_t_st; -static size_t btokBAuthT_deep( - size_t n, size_t f_deep, size_t ec_d, size_t ec_deep); +#define btokBAuthT_state(n, no)\ +/* d */ O_OF_W(n),\ +/* Vct */ O_OF_W(2 * n),\ +/* R */ no / 2 + +static size_t btokBAuthT_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep); size_t btokBAuthT_keep(size_t l) { const size_t n = W_OF_B(2 * l); const size_t no = O_OF_B(2 * l); - return sizeof(bake_bauth_t_o) + - bignStart_keep(l, btokBAuthT_deep) + - 3 * O_OF_W(n) + no / 2; + return sizeof(btok_bauth_t_st) + + memSliceSize( + bakeEcStart_keep(l, btokBAuthT_deep), + btokBAuthT_state(n, no), + SIZE_MAX); } typedef struct { - obj_hdr_t hdr; /*< заголовок */ -// ptr_table { - ec_o* ec; /*< описание эллиптической кривой */ - word* d; /*< [ec->f->n] долговременный личный ключ */ - word* u; /*< [ec->f->n] одноразовый личный ключ */ - octet* V; /*< [ec->f->no] ecX(V) */ - octet* R; /*< [l/8] одноразовый секретный ключ */ -// } bign_params params[1]; /*< параметры */ bake_settings settings[1]; /*< настройки */ bake_cert cert[1]; /*< сертификат */ octet K0[32]; /*< ключ K0 */ - octet data[]; /*< данные */ -} bake_bauth_ct_o; + ec_o* ec; /*< эллиптическая кривая */ + word* d; /*< [n] долговременный личный ключ */ + word* u; /*< [n] одноразовый личный ключ */ + octet* V; /*< [no] ecX(V) */ + octet* R; /*< [no / 2] одноразовый секретный ключ */ + void* stack; /*< [btokBAuthCT_deep] стек */ + mem_align_t data[]; /*< данные */ +} btok_bauth_ct_st; + +static size_t btokBAuthCT_deep(size_t n, size_t f_deep, size_t ec_d, + size_t ec_deep); -static size_t btokBAuthCT_deep( - size_t n, size_t f_deep, size_t ec_d, size_t ec_deep); +#define btokBAuthCT_state(n, no)\ +/* d */ O_OF_W(n),\ +/* u */ O_OF_W(n),\ +/* V */ no,\ +/* R */ no / 2 size_t btokBAuthCT_keep(size_t l) { const size_t n = W_OF_B(2 * l); const size_t no = O_OF_B(2 * l); - return sizeof(bake_bauth_ct_o) + - bignStart_keep(l, btokBAuthCT_deep) + - 2 * O_OF_W(n) + no + no / 2; + return sizeof(btok_bauth_ct_st) + + memSliceSize( + bakeEcStart_keep(l, btokBAuthCT_deep), + btokBAuthCT_state(n, no), + SIZE_MAX); } /* @@ -129,55 +141,50 @@ size_t btokBAuthCT_keep(size_t l) ******************************************************************************* */ +#define btokBAuthTStart_local(n)\ +/* Q */ O_OF_W(2 * n) + err_t btokBAuthTStart(void* state, const bign_params* params, const bake_settings* settings, const octet privkey[], const bake_cert* cert) { err_t code; - bake_bauth_t_o* s = (bake_bauth_t_o*)state; + btok_bauth_t_st* s = (btok_bauth_t_st*)state; size_t n, no; - // стек - word* Q; + word* Q; /* [2 * n] */ void* stack; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(settings, sizeof(bake_settings)) || + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(settings, sizeof(bake_settings)) || settings->kca != TRUE || !memIsNullOrValid(settings->helloa, settings->helloa_len) || - !memIsNullOrValid(settings->hellob, settings->hellob_len)) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (settings->rng == 0) - return ERR_BAD_RNG; - if (!memIsValid(privkey, params->l / 4) || + !memIsNullOrValid(settings->hellob, settings->hellob_len) || + !memIsValid(privkey, params->l / 4) || !memIsValid(cert, sizeof(bake_cert)) || !memIsValid(cert->data, cert->len) || cert->val == 0) return ERR_BAD_INPUT; - // загрузить параметры - code = bignStart(s->data, params); + if (settings->rng == 0) + return ERR_BAD_RNG; + // развернуть кривую + code = bakeEcStart(s->data, params); ERR_CALL_CHECK(code); - s->ec = (ec_o*)s->data; + memSlice(s->data, + objKeep(s->data), SIZE_0, SIZE_MAX, + &s->ec, &stack); n = s->ec->f->n, no = s->ec->f->no; + // разметить состояние и стек + memSlice(stack, + btokBAuthT_state(n, no), SIZE_0, + btokBAuthTStart_local(n), SIZE_0, SIZE_MAX, + &s->d, &s->Vct, &s->R, &s->stack, &Q, &stack); // сохранить параметры memCopy(s->params, params, sizeof(bign_params)); // сохранить настройки memCopy(s->settings, settings, sizeof(bake_settings)); - // настроить указатели - s->d = objEnd(s->ec, word); - s->Vct = s->d + n; - s->R = (octet*)(s->Vct + 2 * n); - // настроить заголовок - s->hdr.keep = sizeof(bake_bauth_t_o) + objKeep(s->ec) + - 3 * O_OF_W(n) + no / 2; - s->hdr.p_count = 3; - s->hdr.o_count = 1; // загрузить личный ключ wwFrom(s->d, privkey, no); - // раскладка стека - Q = objEnd(s, word); - stack = Q + 2 * n; // проверить сертификат и его открытый ключ code = cert->val((octet*)Q, params, cert->data, cert->len); ERR_CALL_CHECK(code); @@ -187,69 +194,64 @@ err_t btokBAuthTStart(void* state, const bign_params* params, return ERR_BAD_CERT; // сохранить сертификат memCopy(s->cert, cert, sizeof(bake_cert)); - // все нормально + // завершение return code; } -static size_t btokBAuthTStart_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +static size_t btokBAuthTStart_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + + return memSliceSize( + btokBAuthTStart_local(n), utilMax(2, f_deep, - ecpIsOnA_deep(n, f_deep)); + ecpIsOnA_deep(n, f_deep)), + SIZE_MAX); } +#define btokBAuthCTStart_local(n)\ +/* Q */ O_OF_W(2 * n) + err_t btokBAuthCTStart(void* state, const bign_params* params, const bake_settings* settings, const octet privkey[], const bake_cert* cert) { err_t code; - bake_bauth_ct_o* s = (bake_bauth_ct_o*)state; + btok_bauth_ct_st* s = (btok_bauth_ct_st*)state; size_t n, no; - // стек - word* Q; + word* Q; /* [2 * n] */ void* stack; - // проверить входные данные - if (!memIsValid(params, sizeof(bign_params)) || - !memIsValid(settings, sizeof(bake_settings)) || + // входной контроль + code = bignParamsCheck(params); + ERR_CALL_CHECK(code); + if (!memIsValid(settings, sizeof(bake_settings)) || settings->kca != TRUE || !memIsNullOrValid(settings->helloa, settings->helloa_len) || - !memIsNullOrValid(settings->hellob, settings->hellob_len)) - return ERR_BAD_INPUT; - if (!bignIsOperable(params)) - return ERR_BAD_PARAMS; - if (settings->rng == 0) - return ERR_BAD_RNG; - if (!memIsValid(privkey, params->l / 4) || + !memIsNullOrValid(settings->hellob, settings->hellob_len) || + !memIsValid(privkey, params->l / 4) || !memIsValid(cert, sizeof(bake_cert)) || !memIsValid(cert->data, cert->len) || cert->val == 0) return ERR_BAD_INPUT; - // загрузить параметры - code = bignStart(s->data, params); + if (settings->rng == 0) + return ERR_BAD_RNG; + // развернуть кривую + code = bakeEcStart(s->data, params); ERR_CALL_CHECK(code); - s->ec = (ec_o*)s->data; + memSlice(s->data, + objKeep(s->data), SIZE_0, SIZE_MAX, + &s->ec, &stack); n = s->ec->f->n, no = s->ec->f->no; + // разметить состояние и стек + memSlice(stack, + btokBAuthCT_state(n, no), SIZE_0, + btokBAuthCTStart_local(n), SIZE_0, SIZE_MAX, + &s->d, &s->u, &s->V, &s->R, &s->stack, &Q, &stack); // сохранить параметры memCopy(s->params, params, sizeof(bign_params)); // сохранить настройки memCopy(s->settings, settings, sizeof(bake_settings)); - // настроить указатели - s->d = objEnd(s->ec, word); - s->u = s->d + n; - s->V = (octet*)(s->u + n); - s->R = s->V + no; - // настроить заголовок - s->hdr.keep = sizeof(bake_bauth_ct_o) + objKeep(s->ec) + - 3 * O_OF_W(n) + no + no / 2; - s->hdr.p_count = 4; - s->hdr.o_count = 1; // загрузить личный ключ wwFrom(s->d, privkey, no); - // раскладка стека - Q = objEnd(s, word); - stack = Q + 2 * n; // проверить сертификат и его открытый ключ code = cert->val((octet*)Q, params, cert->data, cert->len); ERR_CALL_CHECK(code); @@ -259,17 +261,18 @@ err_t btokBAuthCTStart(void* state, const bign_params* params, return ERR_BAD_CERT; // сохранить сертификат memCopy(s->cert, cert, sizeof(bake_cert)); - // все нормально + // завершение return code; } -static size_t btokBAuthCTStart_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +static size_t btokBAuthCTStart_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + + return memSliceSize( + btokBAuthCTStart_local(n), utilMax(2, f_deep, - ecpIsOnA_deep(n, f_deep)); + ecpIsOnA_deep(n, f_deep)), + SIZE_MAX); } /* @@ -278,30 +281,30 @@ static size_t btokBAuthCTStart_deep(size_t n, size_t f_deep, size_t ec_d, ******************************************************************************* */ +#define btokBAuthCTStep2_local(n)\ +/* Vct */ O_OF_W(2 * n),\ +/* Qt */ O_OF_W(2 * n),\ +/* K */ O_OF_W(2 * n) + err_t btokBAuthCTStep2(octet out[], const bake_cert* certt, void* state) { - err_t code; - bake_bauth_ct_o* s = (bake_bauth_ct_o*)state; + err_t code; + btok_bauth_ct_st* s = (btok_bauth_ct_st*)state; size_t n, no; - octet hdr[16]; - // стек word* Vct; /* [2 * n] */ word* Qt; /* [2 * n] */ word* K; /* [2 * n] */ void* stack; // обработать входные данные - if (!objIsOperable(s)) + if (!memIsValid(s, sizeof(btok_bauth_ct_st)) || !ecIsOperable(s->ec)) return ERR_BAD_INPUT; n = s->ec->f->n, no = s->ec->f->no; if (!memIsValid(out, 2 * no + no / 2 + 16)) return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, 2 * no + no / 2 + 16, s, objKeep(s))); - // раскладка стека - Vct = objEnd(s, word); - Qt = Vct + 2 * n; - K = Qt + 2 * n; - stack = K + 2 * n; - ASSERT(32 <= no); + // разметить стек + memSlice(s->stack, + btokBAuthCTStep2_local(n), SIZE_0, SIZE_MAX, + &Vct, &Qt, &K, &stack); // проверить certT code = certt->val((octet*)Qt, s->params, certt->data, certt->len); ERR_CALL_CHECK(code); @@ -326,9 +329,8 @@ err_t btokBAuthCTStep2(octet out[], const bake_cert* certt, void* state) // out <- || belt-keywrap(Rct, 0^16, K) memCopy(out, s->V, no); qrTo(out + no, ecY(Vct, n), s->ec->f, stack); - memSetZero(hdr, 16); qrTo((octet*)K, ecX(K), s->ec->f, stack); - beltKWPWrap(out + 2 * no, s->R, no / 2, hdr, (octet*)K, 32); + beltKWPWrap(out + 2 * no, s->R, no / 2, 0, (octet*)K, 32); // все нормально return ERR_OK; } @@ -336,39 +338,42 @@ err_t btokBAuthCTStep2(octet out[], const bake_cert* certt, void* state) static size_t btokBAuthCTStep2_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { - return O_OF_W(6 * n) + + return memSliceSize( + btokBAuthCTStep2_local(n), utilMax(2, f_deep, - ecMulA_deep(n, ec_d, ec_deep, n)); + ecMulA_deep(n, ec_d, ec_deep, n)), + SIZE_MAX); } +#define btokBAuthTStep3_local(n, no)\ +/* K */ O_OF_W(2 * n),\ +/* Rct */ (no / 2) | SIZE_HI,\ +/* Y */ (size_t)32 | SIZE_HI,\ +/* block0 */ (size_t)16,\ +/* block1 */ (size_t)16 + err_t btokBAuthTStep3(octet out[], const octet in[], void* state) { - bake_bauth_t_o* s = (bake_bauth_t_o*)state; + btok_bauth_t_st* s = (btok_bauth_t_st*)state; size_t n, no; - octet hdr[16]; - // стек word* K; /* [2 * n] общий ключ */ - octet* Rct; /* [l/8] одноразовый секретный ключ (совпадает с K, Y) */ - octet* Y; /* [32] (совпадает c Y) */ - octet* block0; /* [16] (следует за Y) */ - octet* block1; /* [16] (следует за block0) */ + octet* Rct; /* [l/8] одноразовый секретный ключ (|K) */ + octet* Y; /* [32] (|Y) */ + octet* block0; /* [16] */ + octet* block1; /* [16] */ void* stack; - // проверить входные данные - if (!objIsOperable(s)) + // обработать входные данные + if (!memIsValid(s, sizeof(btok_bauth_t_st)) || !ecIsOperable(s->ec)) return ERR_BAD_INPUT; n = s->ec->f->n, no = s->ec->f->no; if (!memIsValid(in, 2 * no + no / 2 + 16) || !memIsValid(out, (8u + s->settings->kcb) ? no / 2 : 0)) return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, (8u + s->settings->kcb) ? - no / 2 : 0, s, objKeep(s))); - // раскладка стека [Y || block0 || block1 должны умещаться в 3 * n слов] - K = objEnd(s, word); - Y = Rct = (octet*)K; - block0 = Y + 32; - block1 = block0 + 16; - stack = Y + MAX2(O_OF_W(2 * n), 32 + 16 + 16); + // разметить стек + memSlice(s->stack, + btokBAuthTStep3_local(n, no), SIZE_0, SIZE_MAX, + &K, &Rct, &Y, &block0, &block1, &stack); // сохранить memCopy(s->Vct, in, 2 * no); // Vb <- in ||..., Vb \in E*? @@ -379,10 +384,9 @@ err_t btokBAuthTStep3(octet out[], const octet in[], void* state) // K <- dt Vct if (!ecMulA(K, s->Vct, s->ec, s->d, n, stack)) return ERR_BAD_PARAMS; - memSetZero(hdr, 16); qrTo((octet*)K, ecX(K), s->ec->f, stack); // Rct <- belt-keyunwrap(Zct, 0^16, K) - if (beltKWPUnwrap(Rct, in + 2 * no, O_OF_B(s->params->l + 128), hdr, + if (beltKWPUnwrap(Rct, in + 2 * no, O_OF_B(s->params->l + 128), 0, (octet*)K, 32) != ERR_OK) return ERR_AUTH; // Y <- beltHash(_l || [_l ||] helloa || hellob) @@ -425,52 +429,57 @@ err_t btokBAuthTStep3(octet out[], const octet in[], void* state) // out <- Tt || Rt memCopy(out + 8, s->R, 16); } - // все нормально + // завершение return ERR_OK; } static size_t btokBAuthTStep3_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { - return MAX2(O_OF_W(2 * n), 32 + 16 + 16) + + return memSliceSize( + btokBAuthTStep3_local(n, O_OF_W(n)), utilMax(5, f_deep, ecMulA_deep(n, ec_d, ec_deep, n), beltHash_keep(), beltKRP_keep(), - beltMAC_keep()); + beltMAC_keep()), + SIZE_MAX); } +#define btokBAuthCTStep4_local(n)\ +/* Y */ (size_t)32,\ +/* t */ O_OF_W(n / 2 + 1) | SIZE_HI,\ +/* K1 */ (size_t)32,\ +/* K2 */ (size_t)32,\ +/* block0 */ (size_t)16,\ +/* block1 */ (size_t)16,\ +/* sct */ O_OF_W(n + n / 2 + 1) + err_t btokBAuthCTStep4(octet out[], const octet in[], void* state) { - bake_bauth_ct_o* s = (bake_bauth_ct_o*)state; + btok_bauth_ct_st* s = (btok_bauth_ct_st*)state; size_t n, no; // стек - octet* Y; /* [32] (совпадает c t, sct) */ - octet* block0; /* [16] (следует перед Y) */ - octet* block1; /* [16] (следует за Y) */ - octet* K1; /* [32] общий ключ (совпадает с Y) */ + octet* Y; /* [32] */ + octet* K1; /* [32] общий ключ */ octet* K2; /* [32] общий ключ */ - word* t; /* [n / 2 + 1] (совпадает c Y, sct) */ - word* sct; /* [n + n / 2 + 1] (совпадает c Y, t) */ + octet* block0; /* [16] */ + octet* block1; /* [16] */ + word* t; /* [n / 2 + 1] (|Y) */ + word* sct; /* [n + n / 2 + 1] */ void* stack; // проверить входные данные - if (!objIsOperable(s)) + if (!memIsValid(s, sizeof(btok_bauth_ct_st)) || !ecIsOperable(s->ec)) return ERR_BAD_INPUT; n = s->ec->f->n, no = s->ec->f->no; if (!memIsValid(in, (8u + s->settings->kcb) ? no / 2 : 0) || !memIsValid(out, s->settings->kcb ? (8u + no + s->cert->len) : 0)) return ERR_BAD_INPUT; - ASSERT(memIsDisjoint2(out, s->settings->kcb ? - (8u + O_OF_B(2 * s->params->l) + s->cert->len) : 0, s, objKeep(s))); - block0 = objEnd(s, octet); - K1 = block0 + 16; - Y = K1 + 32; - t = (word*)Y; - sct = t + n / 2; - block1 = Y + 32; - K2 = (octet*)(sct + n + n / 2 + 1); - stack = K2 + 32; + // разметить стек + memSlice(s->stack, + btokBAuthCTStep4_local(n), SIZE_0, SIZE_MAX, + &Y, &t, &K1, &K2, &block0, &block1, &sct, &stack); // Y <- beltHash(_l || [_l ||] helloa || hellob) beltHashStart(stack); beltHashStepH(s->R, no / 2, stack); @@ -527,55 +536,59 @@ err_t btokBAuthCTStep4(octet out[], const octet in[], void* state) beltMACStepA(out, no + s->cert->len, stack); beltMACStepG(out + no + s->cert->len, stack); } - // все нормально + // завершение return ERR_OK; } static size_t btokBAuthCTStep4_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { - return 16 + 32 + 32 + O_OF_W(2 * n + 1) + + return memSliceSize( + btokBAuthCTStep4_local(n), utilMax(5, f_deep, ecMulA_deep(n, ec_d, ec_deep, n), beltHash_keep(), beltKRP_keep(), - beltMAC_keep()); + beltMAC_keep()), + SIZE_MAX); } +#define btokBAuthTStep5_local(n, no)\ +/* Qct */ O_OF_W(2 * n),\ +/* sct */ O_OF_W(n),\ +/* V */ no,\ +/* t */ O_OF_W(n / 2 + 1) | SIZE_HI,\ +/* block0 */ (size_t)16 + err_t btokBAuthTStep5(const octet in[], size_t in_len, bake_certval_i val_ct, void* state) { err_t code; - bake_bauth_t_o* s = (bake_bauth_t_o*)state; + btok_bauth_t_st* s = (btok_bauth_t_st*)state; size_t n, no; - // стек word* Qct; /* [2 * n] */ word* sct; /* [n] */ octet* V; /* [no] */ - word* t; /* [n / 2 + 1] (совпадает с V) */ - octet* block0; /* [16] (совпадает с Qct) */ + word* t; /* [n / 2 + 1] (|V) */ + octet* block0; /* [16] */ void* stack; - octet mac[8]; // проверить входные данные - if (!objIsOperable(s)) + if (!memIsValid(s, sizeof(btok_bauth_t_st)) || !ecIsOperable(s->ec)) return ERR_BAD_INPUT; n = s->ec->f->n, no = s->ec->f->no; if (!s->settings->kcb) return ERR_BAD_LOGIC; if (in_len < 8 + no || !memIsValid(in, in_len) || val_ct == 0) return ERR_BAD_INPUT; - // раскладка стека - Qct = objEnd(s, word); - block0 = (octet*)Qct; - sct = Qct + 2 * n; - V = (octet*)(sct + n); - t = (word*)V; - stack = V + no; + // разметить стек + memSlice(s->stack, + btokBAuthTStep5_local(n, no), SIZE_0, SIZE_MAX, + &Qct, &sct, &V, &t, &block0, &stack); // Tct == beltMAC(Zct, K1)? beltMACStart(stack, s->K1, 32); beltMACStepA(in, in_len - 8, stack); - beltMACStepG(mac, stack); +// beltMACStepG(mac, stack); if (!beltMACStepV(in + in_len - 8, stack)) return ERR_AUTH; // обработать Zct = [in_len - 8]in @@ -620,28 +633,30 @@ err_t btokBAuthTStep5(const octet in[], size_t in_len, bake_certval_i val_ct, return ERR_BAD_PARAMS; if (!wwEq(Qct, s->Vct, 2 * n)) return ERR_AUTH; - // все нормально + // завершение return ERR_OK; } static size_t btokBAuthTStep5_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { - return O_OF_W(3 * n + n / 2 + 1) + + return memSliceSize( + btokBAuthTStep5_local(n, O_OF_W(n)), utilMax(6, beltHash_keep(), beltMAC_keep(), beltCFB_keep(), f_deep, ecpIsOnA_deep(n, f_deep), - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)); + ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1)), + SIZE_MAX); } static size_t btokBAuthCT_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { return utilMax(3, - btokBAuthCTStart_deep(n, f_deep, ec_d, ec_deep), + btokBAuthCTStart_deep(n, f_deep), btokBAuthCTStep2_deep(n, f_deep, ec_d, ec_deep), btokBAuthCTStep4_deep(n, f_deep, ec_d, ec_deep)); } @@ -650,7 +665,7 @@ static size_t btokBAuthT_deep(size_t n, size_t f_deep, size_t ec_d, size_t ec_deep) { return utilMax(3, - btokBAuthTStart_deep(n, f_deep, ec_d, ec_deep), + btokBAuthTStart_deep(n, f_deep), btokBAuthTStep3_deep(n, f_deep, ec_d, ec_deep), btokBAuthTStep5_deep(n, f_deep, ec_d, ec_deep)); } @@ -663,26 +678,24 @@ static size_t btokBAuthT_deep(size_t n, size_t f_deep, size_t ec_d, err_t btokBAuthCTStepG(octet key[32], void* state) { - bake_bauth_ct_o* s = (bake_bauth_ct_o*)state; + btok_bauth_ct_st* s = (btok_bauth_ct_st*)state; // проверить входные данные - if (!objIsOperable(s) || + if (!memIsValid(s, sizeof(btok_bauth_ct_st)) || !ecIsOperable(s->ec) || !memIsValid(key, 32)) return ERR_BAD_INPUT; // key <- K0 memCopy(key, s->K0, 32); - // все нормально return ERR_OK; } err_t btokBAuthTStepG(octet key[32], void* state) { - bake_bauth_t_o* s = (bake_bauth_t_o*)state; + btok_bauth_t_st* s = (btok_bauth_t_st*)state; // проверить входные данные - if (!objIsOperable(s) || + if (!memIsValid(s, sizeof(btok_bauth_t_st)) || !ecIsOperable(s->ec) || !memIsValid(key, 32)) return ERR_BAD_INPUT; // key <- K0 memCopy(key, s->K0, 32); - // все нормально return ERR_OK; } diff --git a/src/crypto/btok/btok_cvc.c b/src/crypto/btok/btok_cvc.c index 05757d0f..bb04f93b 100644 --- a/src/crypto/btok/btok_cvc.c +++ b/src/crypto/btok/btok_cvc.c @@ -4,7 +4,7 @@ \brief STB 34.101.79 (btok): CV certificates \project bee2 [cryptographic library] \created 2022.07.04 -\version 2025.05.12 +\version 2025.09.15 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -108,37 +108,38 @@ static err_t btokSign(octet sig[], const void* buf, size_t count, bign_params params[1]; octet oid_der[16]; size_t oid_len = sizeof(oid_der); - void* stack; - octet* hash; - octet* t; - size_t t_len; void* state; + octet* hash; /* [privkey_len] */ + octet* t; /* [privkey_len] */ + void* hash_state; /* [beltHash_keep() || bashHash_keep()] */ + size_t t_len; // загрузить параметры code = btokParamsStd(params, privkey_len); ERR_CALL_CHECK(code); - // создать и разметить стек - stack = blobCreate(2 * privkey_len + - (privkey_len <= 32 ? beltHash_keep() : bashHash_keep())); - if (!stack) + // создать состояние + state = blobCreate2( + privkey_len, + privkey_len, + privkey_len <= 32 ? beltHash_keep() : bashHash_keep(), + SIZE_MAX, + &hash, &t, &hash_state); + if (state == 0) return ERR_OUTOFMEMORY; - hash = (octet*)stack; - t = hash + privkey_len; - state = t + privkey_len; // хэшировать if (privkey_len <= 32) { - beltHashStart(state); - beltHashStepH(buf, count, state); - beltHashStepG2(hash, privkey_len, state); + beltHashStart(hash_state); + beltHashStepH(buf, count, hash_state); + beltHashStepG2(hash, privkey_len, hash_state); code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81"); ERR_CALL_HANDLE(code, blobClose(state)); ASSERT(oid_len == 11); } else { - bashHashStart(state, privkey_len * 4); - bashHashStepH(buf, count, state); - bashHashStepG(hash, privkey_len, state); + bashHashStart(hash_state, privkey_len * 4); + bashHashStepH(buf, count, hash_state); + bashHashStepG(hash, privkey_len, hash_state); code = bignOidToDER(oid_der, &oid_len, privkey_len == 48 ? "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13"); ERR_CALL_HANDLE(code, blobClose(state)); @@ -157,7 +158,7 @@ static err_t btokSign(octet sig[], const void* buf, size_t count, code = bignSign2(sig, params, oid_der, oid_len, hash, privkey, t, t_len); // завершить - blobClose(stack); + blobClose(state); return code; } @@ -168,37 +169,38 @@ static err_t btokVerify(const void* buf, size_t count, const octet sig[], bign_params params[1]; octet oid_der[16]; size_t oid_len = sizeof(oid_der); - void* stack; - octet* hash; void* state; + octet* hash; /* [pubkey_len / 2] */ + void* hash_state; /* [beltHash_keep() || bashHash_keep()] */ // входной контроль if (pubkey_len % 2) return ERR_BAD_INPUT; // загрузить параметры code = btokParamsStd(params, pubkey_len / 2); ERR_CALL_CHECK(code); - // создать и разметить стек - stack = blobCreate(pubkey_len / 2 + - (pubkey_len <= 64 ? beltHash_keep() : bashHash_keep())); - if (!stack) + // создать состояние + state = blobCreate2( + pubkey_len / 2, + pubkey_len <= 64 ? beltHash_keep() : bashHash_keep(), + SIZE_MAX, + &hash, &hash_state); + if (state == 0) return ERR_OUTOFMEMORY; - hash = (octet*)stack; - state = hash + pubkey_len / 2; // хэшировать if (pubkey_len <= 64) { - beltHashStart(state); - beltHashStepH(buf, count, state); - beltHashStepG2(hash, pubkey_len / 2, state); + beltHashStart(hash_state); + beltHashStepH(buf, count, hash_state); + beltHashStepG2(hash, pubkey_len / 2, hash_state); code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81"); ERR_CALL_HANDLE(code, blobClose(state)); ASSERT(oid_len == 11); } else { - bashHashStart(state, pubkey_len * 2); - bashHashStepH(buf, count, state); - bashHashStepG(hash, pubkey_len / 2, state); + bashHashStart(hash_state, pubkey_len * 2); + bashHashStepH(buf, count, hash_state); + bashHashStepG(hash, pubkey_len / 2, hash_state); code = bignOidToDER(oid_der, &oid_len, pubkey_len == 96 ? "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13"); ERR_CALL_HANDLE(code, blobClose(state)); @@ -209,14 +211,14 @@ static err_t btokVerify(const void* buf, size_t count, const octet sig[], code = bign96PubkeyVal(params, pubkey); else code = bignPubkeyVal(params, pubkey); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); // проверить подпись if (pubkey_len == 48) code = bign96Verify(params, oid_der, oid_len, hash, sig, pubkey); else code = bignVerify(params, oid_der, oid_len, hash, sig, pubkey); // завершить - blobClose(stack); + blobClose(state); return code; } @@ -630,26 +632,28 @@ err_t btokCVCVal(const octet cert[], size_t cert_len, const octet certa[], size_t certa_len, const octet* date) { err_t code; - void* stack; - btok_cvc_t* cvc; - btok_cvc_t* cvca; + void* state; + btok_cvc_t* cvc; /* [1] */ + btok_cvc_t* cvca; /* [1] */ // входной контроль if (!memIsNullOrValid(date, 6)) return ERR_BAD_INPUT; - // выделить и разметить память - stack = blobCreate(2 * sizeof(btok_cvc_t)); - if (!stack) + // слздать состояние + state = blobCreate2( + sizeof(btok_cvc_t), + sizeof(btok_cvc_t), + SIZE_MAX, + &cvc, &cvca); + if (state == 0) return ERR_OUTOFMEMORY; - cvc = (btok_cvc_t*)stack; - cvca = cvc + 1; // разобрать сертификаты code = btokCVCUnwrap(cvca, certa, certa_len, 0, 0); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); code = btokCVCUnwrap(cvc, cert, cert_len, cvca->pubkey, cvca->pubkey_len); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); // проверить соответствие code = btokCVCCheck2(cvc, cvca); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); // проверить дату if (date) { @@ -659,7 +663,7 @@ err_t btokCVCVal(const octet cert[], size_t cert_len, code = ERR_OUTOFRANGE; } // завершить - blobClose(stack); + blobClose(state); return code; } @@ -667,7 +671,7 @@ err_t btokCVCVal2(btok_cvc_t* cvc, const octet cert[], size_t cert_len, const btok_cvc_t* cvca, const octet* date) { err_t code; - void* stack = 0; + void* state = 0; // входной контроль if (!memIsNullOrValid(cvc, sizeof(btok_cvc_t)) || !memIsValid(cvca, sizeof(btok_cvc_t)) || @@ -676,17 +680,17 @@ err_t btokCVCVal2(btok_cvc_t* cvc, const octet cert[], size_t cert_len, // выделить память if (!cvc) { - stack = blobCreate(sizeof(btok_cvc_t)); - if (!stack) + state = blobCreate(sizeof(btok_cvc_t)); + if (state == 0) return ERR_OUTOFMEMORY; - cvc = (btok_cvc_t*)stack; + cvc = (btok_cvc_t*)state; } // разобрать сертификат code = btokCVCUnwrap(cvc, cert, cert_len, cvca->pubkey, cvca->pubkey_len); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); // проверить соответствие code = btokCVCCheck2(cvc, cvca); - ERR_CALL_HANDLE(code, blobClose(stack)); + ERR_CALL_HANDLE(code, blobClose(state)); // проверить дату if (date) { @@ -696,7 +700,7 @@ err_t btokCVCVal2(btok_cvc_t* cvc, const octet cert[], size_t cert_len, code = ERR_OUTOFRANGE; } // завершить - blobClose(stack); + blobClose(state); return code; } diff --git a/src/crypto/btok/btok_sm.c b/src/crypto/btok/btok_sm.c index 603e7495..b3f5e3dc 100644 --- a/src/crypto/btok/btok_sm.c +++ b/src/crypto/btok/btok_sm.c @@ -4,7 +4,7 @@ \brief STB 34.101.79 (btok): Secure Messaging \project bee2 [cryptographic library] \created 2022.10.31 -\version 2025.06.10 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -29,16 +29,16 @@ */ typedef struct { - octet key1[32]; /*!< ключ belt-mac */ - octet key2[32]; /*!< ключ belt-cfb */ - octet ctr[16]; /*!< счетчик */ - octet stack[]; /*!< стек */ + octet key1[32]; /*!< ключ belt-mac */ + octet key2[32]; /*!< ключ belt-cfb */ + octet ctr[16]; /*!< счетчик */ + mem_align_t stack[]; /*!< стек */ } btok_sm_st; size_t btokSM_keep() { - return sizeof(btok_sm_st) + utilMax(3, - beltKRP_keep(), beltMAC_keep(), beltCFB_keep()); + return sizeof(btok_sm_st) + + utilMax(3, beltKRP_keep(), beltMAC_keep(), beltCFB_keep()); } void btokSMStart(void* state, const octet key[32]) diff --git a/src/crypto/dstu.c b/src/crypto/dstu.c index 07b94f7e..71449b32 100644 --- a/src/crypto/dstu.c +++ b/src/crypto/dstu.c @@ -4,7 +4,7 @@ \brief DSTU 4145-2002 (Ukraine): digital signature algorithms \project bee2 [cryptographic library] \created 2012.04.27 -\version 2025.06.10 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -21,23 +21,6 @@ #include "bee2/math/ww.h" #include "bee2/math/zz.h" -/* -******************************************************************************* -Глубина стека - -Высокоуровневые функции сообщают о потребностях в стековой памяти через -функции интерфейса dstu_deep_i. Потребности не должны учитывать память для -размещения описаний базового поля и эллиптической кривой. -******************************************************************************* -*/ - -typedef size_t (*dstu_deep_i)( - size_t n, /* размерность (в машинных словах) */ - size_t f_deep, /* глубина стека базового поля */ - size_t ec_d, /* число проективных координат */ - size_t ec_deep /* глубина стека эллиптической кривой */ -); - /* ******************************************************************************* Стандартные параметры: dstu_163pb @@ -347,7 +330,6 @@ static octet _curve431pb_c = 2; memCopy((params)->n, _##name##_n, sizeof(_##name##_n));\ (params)->c = _##name##_c;\ - err_t dstuParamsStd(dstu_params* params, const char* name) { if (!memIsValid(params, sizeof(dstu_params))) @@ -409,102 +391,101 @@ err_t dstuParamsStd(dstu_params* params, const char* name) /* ******************************************************************************* -Создание описания эллиптической кривой +Создание эллиптической кривой + +По долговременным параметрам params создается эллиптическая кривая. Указатель +на описание кривой возвращается |pec. -По долговременным параметрам params формируется описание pec эллиптической -кривой. Указатель *pec является одновременно началом фрагмента памяти, -в котором размещается состояние и стек. Длина фрагмента определяется с учетом -потребностей deep и размерностей dims. \pre Указатель pec корректен. -\return ERR_OK, если описание успешно создано, и код ошибки в противном -случае. -\remark Запрошенная память начинается по адресу objEnd(*pec, void). +\return ERR_OK, если кривая успешно создана, и код ошибки в противном случае. \remark Проводится минимальная проверка параметров, обеспечивающая работоспособность высокоуровневых функций. ******************************************************************************* */ static err_t dstuEcCreate( - ec_o** pec, /* [out] описание эллиптической кривой */ - const dstu_params* params, /* [in] долговременные параметры */ - dstu_deep_i deep /* [in] потребности в стековой памяти */ + ec_o** pec, /* [out] эллиптическая кривая */ + const dstu_params* params /* [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; /* кривая */ + ec_o* ec; /* [ec2CreateLD_keep(n)] кривая */ + qr_o* f; /* [gf2Create_keep(m)] поле */ + // второе состояние + void* state1; + size_t* p; /* [4] многочлен */ + octet* A; /* [no] коэффициент A (|p) */ void* stack; - // pre - ASSERT(memIsValid(pec, sizeof(*pec))); - // минимальная проверка входных данных + // входной контроль if (!memIsValid(params, sizeof(dstu_params)) || - (m = params->p[0]) < 160 || m > 509 || + !memIsValid(pec, sizeof(*pec))) + return ERR_BAD_INPUT; + if ((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))); + state = blobCreate2( + ec2CreateLD_keep(n), + gf2Create_keep(m), + SIZE_MAX, + &ec, &f); if (state == 0) return ERR_OUTOFMEMORY; - // создать поле - f = (qr_o*)((octet*)state + ec_keep); - p = (size_t*)((octet*)f + f_keep); + // создать второе состояние + state1 = blobCreate2( + sizeof(size_t) * 4, + O_OF_B(n) | SIZE_HI, + utilMax(3, + gf2Create_deep(m), + ec2CreateLD_deep(n, f_deep), + ecGroupCreate_deep(f_deep)), + SIZE_MAX, + &p, &A, &stack); + if (state1 == 0) + { + blobClose(state); + return ERR_OUTOFMEMORY; + } + // создать поле кривую и группу 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(state1); 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, + !ecGroupCreate(ec, params->P, params->P + ec->f->no, params->n, ec->f->no, params->c, stack)) { + blobClose(state1); blobClose(state); return ERR_BAD_PARAMS; } // присоединить f к ec objAppend(ec, f, 0); - // все нормально + // завершить + blobClose(state1); *pec = ec; return ERR_OK; } /* ******************************************************************************* -Закрытие описания эллиптической кривой +Закрытие эллиптической кривой ******************************************************************************* */ @@ -537,34 +518,42 @@ static void dstuEcClose(ec_o* ec) ******************************************************************************* */ -static size_t dstuParamsVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return utilMax(4, - ec2IsValid_deep(n), - ec2SeemsValidGroup_deep(n, f_deep), - ec2IsSafeGroup_deep(n), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); -} - -err_t dstuParamsVal(const dstu_params* params) +static err_t dstuParamsValEc(const ec_o* ec) { - err_t code; - // состояние - ec_o* ec = 0; void* stack; - // старт - code = dstuEcCreate(&ec, params, dstuParamsVal_deep); - ERR_CALL_CHECK(code); - stack = objEnd(ec, void); + // pre + ASSERT(ecIsOperable(ec)); + // создать стек + stack = blobCreate( + utilMax(4, + ec2IsValid_deep(ec->f->n), + ec2GroupSeemsValid_deep(ec->f->n, ec->f->deep), + ec2GroupIsSafe_deep(ec->f->n), + ecHasOrderA_deep(ec->f->n, ec->d, ec->deep, ec->f->n))); + if (stack == 0) + return ERR_OUTOFMEMORY; // проверить кривую и базовую точку if (wwBitSize(ec->order, ec->f->n) <= 160 || !ec2IsValid(ec, stack) || - !ec2SeemsValidGroup(ec, stack) || - !ec2IsSafeGroup(ec, 32, stack) || + !ec2GroupSeemsValid(ec, stack) || + !ec2GroupIsSafe(ec, 32, stack) || !ecHasOrderA(ec->base, ec, ec->order, ec->f->n, stack)) - code = ERR_BAD_PARAMS; + { + blobClose(stack); + return ERR_BAD_PARAMS; + } // завершение + blobClose(stack); + return ERR_OK; +} + +err_t dstuParamsVal(const dstu_params* params) +{ + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuParamsValEc(ec); dstuEcClose(ec); return code; } @@ -575,42 +564,37 @@ err_t dstuParamsVal(const dstu_params* params) ******************************************************************************* */ -static size_t dstuPointGen_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + - utilMax(2, - gf2QSolve_deep(n, f_deep), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); -} - -err_t dstuPointGen(octet point[], const dstu_params* params, gen_i rng, - void* rng_state) +static err_t dstuPointGenEc(octet point[], const ec_o* ec, + gen_i rng, void* rng_state) { - err_t code; - // состояние - ec_o* ec = 0; - word* x; - word* y; - word* t; + size_t m; + void* state; + word* R; /* [2 * n] */ + word* x; /* [n] */ + word* y; /* [n] */ + word* t; /* [n] */ void* stack; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // старт - code = dstuEcCreate(&ec, params, dstuPointGen_deep); - ERR_CALL_CHECK(code); - // проверить входные указатели + // pre + ASSERT(ecIsOperable(ec)); + // размерность order + m = W_OF_B(wwBitSize(ec->order, ec->f->n)); + // входной контроль if (!memIsValid(point, 2 * ec->f->no)) - { - dstuEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - x = objEnd(ec, word); - y = x + ec->f->n; - t = y + ec->f->n; - stack = t + ec->f->n; + if (rng == 0) + return ERR_BAD_RNG; + // создать состояние + state = blobCreate2( + O_OF_W(2 * ec->f->n), + O_OF_W(ec->f->n), + utilMax(2, + gf2QSolve_deep(ec->f->n, ec->f->deep), + ecHasOrderA_deep(ec->f->n, ec->d, ec->deep, ec->f->n)), + SIZE_MAX, + &R, &t, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; + x = R, y = R + ec->f->n; // пока точка не сгенерирована while (1) { @@ -629,98 +613,113 @@ err_t dstuPointGen(octet point[], const dstu_params* params, gen_i rng, 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)) + ecHasOrderA(R, ec, ec->order, m, stack)) break; } // выгрузить точку qrTo(point, x, ec->f, stack); qrTo(point + ec->f->no, y, ec->f, stack); // завершение - dstuEcClose(ec); + blobClose(state); return ERR_OK; } -static size_t dstuPointVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t dstuPointGen(octet point[], const dstu_params* params, gen_i rng, + void* rng_state) { - return O_OF_W(2 * n) + - utilMax(2, - ec2IsOnA_deep(n, f_deep), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuPointGenEc(point, ec, rng, rng_state); + dstuEcClose(ec); + return code; } -err_t dstuPointVal(const dstu_params* params, const octet point[]) +static err_t dstuPointValEc(const ec_o* ec, const octet point[]) { - err_t code; - // состояние - ec_o* ec = 0; - word* x; - word* y; + size_t m; + void* state; + word* R; /* [2 * n] */ + word* x; /* [n] */ + word* y; /* [n] */ void* stack; - // старт - code = dstuEcCreate(&ec, params, dstuPointVal_deep); - ERR_CALL_CHECK(code); - // проверить входные указатели + // pre + ASSERT(ecIsOperable(ec)); + // размерность order + m = W_OF_B(wwBitSize(ec->order, ec->f->n)); + // входной контроль if (!memIsValid(point, 2 * ec->f->no)) - { - dstuEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - x = objEnd(ec, word); - y = x + ec->f->n; - stack = y + ec->f->n; + // создать состояние + state = blobCreate2( + O_OF_W(2 * ec->f->n), + utilMax(2, + ec2IsOnA_deep(ec->f->n, ec->f->deep), + ecHasOrderA_deep(ec->f->n, ec->d, ec->deep, ec->f->n)), + SIZE_MAX, + &R, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; + x = R, y = R + 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; + !ec2IsOnA(R, ec, stack) || + !ecHasOrderA(R, ec, ec->order, m, stack)) + { + blobClose(state); + return ERR_BAD_POINT; + } // завершение - dstuEcClose(ec); - return code; + blobClose(state); + return ERR_OK; } -static size_t dstuPointCompress_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t dstuPointVal(const dstu_params* params, const octet point[]) { - return O_OF_W(2 * n) + gf2Tr_deep(n, f_deep); + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuPointValEc(ec, point); + dstuEcClose(ec); + return code; } -err_t dstuPointCompress(octet xpoint[], const dstu_params* params, +static err_t dstuPointCompressEc(octet xpoint[], const ec_o* ec, const octet point[]) { - err_t code; - // состояние - ec_o* ec = 0; - word* x; - word* y; + void* state; + word* x; /* [n] */ + word* y; /* [n] */ void* stack; - // старт - code = dstuEcCreate(&ec, params, dstuPointCompress_deep); - ERR_CALL_CHECK(code); + // pre + ASSERT(ecIsOperable(ec)); // проверить входные указатели if (!memIsValid(point, 2 * ec->f->no) || !memIsValid(xpoint, ec->f->no)) - { - dstuEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - x = objEnd(ec, word); - y = x + ec->f->n; - stack = y + ec->f->n; + // создать состояние + state = blobCreate2( + O_OF_W(ec->f->n), + O_OF_W(ec->f->n), + gf2Tr_deep(ec->f->n, ec->f->deep), + SIZE_MAX, + &x, &y, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // загрузить точку if (!qrFrom(x, point, ec->f, stack) || !qrFrom(y, point + ec->f->no, ec->f, stack)) { - dstuEcClose(ec); + blobClose(state); return ERR_BAD_POINT; } // x == 0? if (wwIsZero(x, ec->f->n)) { - dstuEcClose(ec); + blobClose(state); return ERR_OK; } // y <- y / x @@ -730,47 +729,51 @@ err_t dstuPointCompress(octet xpoint[], const dstu_params* params, xpoint[0] &= 0xFE; xpoint[0] |= gf2Tr(y, ec->f, stack); // завершение - dstuEcClose(ec); + blobClose(state); return ERR_OK; } -static size_t dstuPointRecover_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +err_t dstuPointCompress(octet xpoint[], const dstu_params* params, + const octet point[]) { - return O_OF_W(2 * n) + - utilMax(2, - gf2QSolve_deep(n, f_deep), - gf2Tr_deep(n, f_deep)); + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuPointCompressEc(xpoint, ec, point); + dstuEcClose(ec); + return code; } -err_t dstuPointRecover(octet point[], const dstu_params* params, +static err_t dstuPointRecoverEc(octet point[], const ec_o* ec, const octet xpoint[]) { - err_t code; register bool_t trace; - // состояние - ec_o* ec = 0; - word* x; - word* y; + void* state; + word* x; /* [n] */ + word* y; /* [n] */ void* stack; - // старт - code = dstuEcCreate(&ec, params, dstuPointRecover_deep); - ERR_CALL_CHECK(code); - // проверить входные указатели + // pre + ASSERT(ecIsOperable(ec)); + // входной контроль if (!memIsValid(xpoint, ec->f->no) || !memIsValid(point, 2 * ec->f->no)) - { - dstuEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - x = objEnd(ec, word); - y = x + ec->f->n; - stack = y + ec->f->n; + // создать состояние + state = blobCreate2( + O_OF_W(ec->f->n), + O_OF_W(ec->f->n), + utilMax(2, + gf2QSolve_deep(ec->f->n, ec->f->deep), + gf2Tr_deep(ec->f->n, ec->f->deep)), + SIZE_MAX, + &x, &y, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // загрузить сжатое представление точки if (!qrFrom(x, xpoint, ec->f, stack)) { - dstuEcClose(ec); + blobClose(state); return ERR_BAD_POINT; } // x == 0? @@ -783,25 +786,25 @@ err_t dstuPointRecover(octet point[], const dstu_params* params, // выгрузить y-координату qrTo(point + ec->f->n, ec->B, ec->f, stack); // все нормально - dstuEcClose(ec); + blobClose(state); return ERR_OK; } // восстановить первый разряд x trace = wwTestBit(x, 0); wwSetBit(x, 0, 0); - if (gf2Tr(x, ec->f, stack) != (bool_t)params->A) + if (gf2Tr(x, ec->f, stack) != (bool_t)ec->A[0]) 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) + if (ec->A[0]) wwFlipBit(y, 0); // Solve[z^2 + z == y] if (!gf2QSolve(y, ec->f->unity, y, ec->f, stack)) { CLEAN(trace); - dstuEcClose(ec); + blobClose(state); return ERR_BAD_PARAMS; } // tr(y) == trace? @@ -815,8 +818,20 @@ err_t dstuPointRecover(octet point[], const dstu_params* params, // выгрузить точку qrTo(point, x, ec->f, stack); qrTo(point + ec->f->no, y, ec->f, stack); - // все нормально + // завершение CLEAN(trace); + blobClose(state); + return ERR_OK; +} + +err_t dstuPointRecover(octet point[], const dstu_params* params, + const octet xpoint[]) +{ + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuPointRecoverEc(point, ec, xpoint); dstuEcClose(ec); return code; } @@ -827,136 +842,129 @@ err_t dstuPointRecover(octet point[], const dstu_params* params, ******************************************************************************* */ -static size_t dstuKeypairGen_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - -err_t dstuKeypairGen(octet privkey[], octet pubkey[], - const dstu_params* params, gen_i rng, void* rng_state) +static err_t dstuKeypairGenEc(octet privkey[], octet pubkey[], const ec_o* ec, + gen_i rng, void* rng_state) { - err_t code; - size_t order_n, order_no, order_nb; - // состояние - ec_o* ec = 0; - word* d; - word* x; - word* y; + size_t m, mo, mb; + void* state; + word* d; /* [m] */ + word* Q; /* [2 * n] */ void* stack; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // старт - code = dstuEcCreate(&ec, params, dstuKeypairGen_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) || + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mb = wwBitSize(ec->order, ec->f->n); + mo = O_OF_B(mb); + m = W_OF_B(mb); + // входной контроль + if (!memIsValid(privkey, mo) || !memIsValid(pubkey, 2 * ec->f->no)) - { - dstuEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - x = d + ec->f->n; - y = x + ec->f->n; - stack = y + ec->f->n; + if (rng == 0) + return ERR_BAD_RNG; + // создать состояние + state = blobCreate2( + O_OF_W(m), + O_OF_W(2 * ec->f->n), + ecMulA_deep(ec->f->n, ec->d, ec->deep, m), + SIZE_MAX, + &d, &Q, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // d <-R {1,2,..., order - 1} // [алгоритм из раздела 6.3 ДСТУ --- обрезка d] - wwSetZero(d, order_n); + wwSetZero(d, m); 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); + rng(d, mo, rng_state); + wwFrom(d, d, mo); + wwTrimHi(d, m, mb - 1); + ASSERT(wwCmp(d, ec->order, m) < 0); // 0 < d? - if (!wwIsZero(d, order_n)) + if (!wwIsZero(d, m)) break; } // Q <- d G - if (!ecMulA(x, ec->base, ec, d, order_n, stack)) + if (!ecMulA(Q, ec->base, ec, d, m, stack)) { // если params корректны, то этого быть не должно - dstuEcClose(ec); + blobClose(state); return ERR_BAD_PARAMS; } // Q <- -Q - ec2NegA(x, x, ec); + ec2NegA(Q, Q, ec); // выгрузить ключи - wwTo(privkey, order_no, d); - qrTo(pubkey, x, ec->f, stack); - qrTo(pubkey + ec->f->no, y, ec->f, stack); - // все нормально + wwTo(privkey, mo, d); + qrTo(pubkey, ecX(Q), ec->f, stack); + qrTo(pubkey + ec->f->no, ecY(Q, ec->f->n), ec->f, stack); + // завершение + blobClose(state); + return ERR_OK; +} + +err_t dstuKeypairGen(octet privkey[], octet pubkey[], + const dstu_params* params, gen_i rng, void* rng_state) +{ + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuKeypairGenEc(privkey, pubkey, ec, rng, rng_state); dstuEcClose(ec); return code; } /* ******************************************************************************* -ЭЦП +Выработка ЭЦП ******************************************************************************* */ -static size_t dstuSign_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(6 * n) + - utilMax(2, - ecMulA_deep(n, ec_d, ec_deep, n), - zzMulMod_deep(n)); -} - -err_t dstuSign(octet sig[], const dstu_params* params, size_t ld, +static err_t dstuSignEc(octet sig[], const ec_o* ec, 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 = 0; - word* e; /* эфемерный лк */ - word* h; /* хэш-значение как элемент поля */ - word* x; /* х-координата эфемерного ок */ - word* y; /* y-координата эфемерного ок */ - word* r; /* первая часть ЭЦП */ - word* s; /* вторая часть ЭЦП */ + size_t m, mo, mb; + void* state; + word* e; /* [m] эфемерный лк */ + word* h; /* [n] хэш-значение как элемент поля */ + word* R; /* [2 * n] эфемерный ок */ + word* x; /* [n] x-координата R */ + word* y; /* [n] y-координата R */ + word* r; /* [m] первая часть ЭЦП */ + word* s; /* [m] вторая часть ЭЦП */ void* stack; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // старт - code = dstuEcCreate(&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 || + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mb = wwBitSize(ec->order, ec->f->n); + mo = O_OF_B(mb); + m = W_OF_B(mb); + // входной контроль + // * шаги 1, 2: проверка params, privkey + // * шаг 3: проверить ld + if (!memIsValid(privkey, mo) || + ld % 16 != 0 || ld < 16 * mo || !memIsValid(hash, hash_len) || !memIsValid(sig, O_OF_B(ld))) - { - dstuEcClose(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; + if (rng == 0) + return ERR_BAD_RNG; + // создать состояние + state = blobCreate2( + O_OF_W(m), + O_OF_W(ec->f->n), + O_OF_W(2 * ec->f->n), + O_OF_W(m), + O_OF_W(m), + utilMax(2, + ecMulA_deep(ec->f->n, ec->d, ec->deep, m), + zzMulMod_deep(m)), + SIZE_MAX, + &e, &h, &R, &r, &s, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; + x = R, y = R + ec->f->n; // шаги 4 -- 6: хэширование // шаг 7: перевести hash в элемент основного поля h // [алгоритм из раздела 5.9 ДСТУ] @@ -980,18 +988,18 @@ err_t dstuSign(octet sig[], const dstu_params* params, size_t ld, 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)) + rng(e, mo, rng_state); + wwFrom(e, e, mo); + wwTrimHi(e, m, mb - 1); + ASSERT(wwCmp(e, ec->order, m) < 0); + if (!wwIsZero(e, m)) break; } - // шаг 8: (x, y) <- e G - if (!ecMulA(x, ec->base, ec, e, order_n, stack)) + // шаг 8: R = (x, y) <- e G + if (!ecMulA(R, ec->base, ec, e, m, stack)) { // если params корректны, то этого быть не должно - dstuEcClose(ec); + blobClose(state); return ERR_BAD_PARAMS; } // шаг 8: если x == 0, то повторить генерацию @@ -1000,81 +1008,95 @@ err_t dstuSign(octet sig[], const dstu_params* params, size_t ld, // шаг 9: y <- x * h qrMul(y, x, h, ec->f, stack); // шаг 10: r <- \bar{y} - ASSERT(order_n <= ec->f->n); + ASSERT(m <= ec->f->n); qrTo((octet*)r, y, ec->f, stack); - wwFrom(r, r, order_no); - wwTrimHi(r, order_n, order_nb - 1); + wwFrom(r, r, mo); + wwTrimHi(r, m, mb - 1); // шаг 11: если r = 0, то повторить генерацию - if (wwIsZero(r, order_n)) + if (wwIsZero(r, m)) 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); + wwFrom(s, privkey, mo); + zzMulMod(s, s, r, ec->order, m, stack); + zzAddMod(s, s, e, ec->order, m); // шаг 13: если s = 0, то повторить генерацию - if (wwIsZero(s, order_n)) + if (wwIsZero(s, m)) 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); - // все нормально - dstuEcClose(ec); - return code; + wwTo(sig, mo, r); + wwTo(sig + ld / 16, mo, s); + // завершение + blobClose(state); + return ERR_OK; } -static size_t dstuVerify_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +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) { - return O_OF_W(5 * n) + - ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n); + err_t code; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuSignEc(sig, ec, ld, hash, hash_len, privkey, rng, + rng_state); + dstuEcClose(ec); + return code; } -err_t dstuVerify(const dstu_params* params, size_t ld, const octet hash[], +/* +******************************************************************************* +Проверка ЭЦП +******************************************************************************* +*/ + +static err_t dstuVerifyEc(const ec_o* ec, 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 = 0; - word* h; /* хэш-значение как элемент поля */ - word* x; /* х-координата эфемерного ок */ - word* y; /* y-координата эфемерного ок */ - word* r; /* первая часть ЭЦП */ - word* s; /* вторая часть ЭЦП */ + size_t m, mo, mb, i; + void* state; + word* h; /* [n] хэш-значение как элемент поля */ + word* R; /* [2 * n] долговременный / эфемерный ок */ + word* x; /* [n] x-координата R */ + word* y; /* [n] y-координата R */ + word* r; /* [m] первая часть ЭЦП */ + word* s; /* [m] вторая часть ЭЦП */ void* stack; - // старт - code = dstuEcCreate(&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 + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mb = wwBitSize(ec->order, ec->f->n); + mo = O_OF_B(mb); + m = W_OF_B(mb); + // входной контроль + // * шаги 1, 2: обработка идентификатора хэш-функции + // * шаг 3: проверить ld if (!memIsValid(pubkey, 2 * ec->f->no) || - ld % 16 != 0 || ld < 16 * order_no || + ld % 16 != 0 || ld < 16 * mo || !memIsValid(hash, hash_len)) - { - dstuEcClose(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; + // создать состояние + state = blobCreate2( + O_OF_W(ec->f->n), + O_OF_W(2 * ec->f->n), + O_OF_W(m), + O_OF_W(m), + ecAddMulA_deep(ec->f->n, ec->d, ec->deep, 2, ec->f->n, m), + SIZE_MAX, + &h, &R, &r, &s, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; + x = R, y = R + ec->f->n; // шаг 4: проверить params // шаг 5: проверить pubkey // [минимальная проверка принадлежности координат базовому полю] if (!qrFrom(x, pubkey, ec->f, stack) || !qrFrom(y, pubkey + ec->f->no, ec->f, stack)) { - dstuEcClose(ec); + blobClose(state); return ERR_BAD_PUBKEY; } // шаги 6, 7: хэширование @@ -1096,40 +1118,51 @@ err_t dstuVerify(const dstu_params* params, size_t ld, const octet hash[], 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) + wwFrom(r, sig, mo); + wwFrom(s, sig + ld / 16, mo); + for (i = mo; i < ld / 16; ++i) if (sig[i] || sig[i + ld / 16]) { - dstuEcClose(ec); + blobClose(state); 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) + if (wwIsZero(r, m) || + wwIsZero(s, m) || + wwCmp(r, ec->order, m) >= 0 || + wwCmp(s, ec->order, m) >= 0) { - dstuEcClose(ec); + blobClose(state); return ERR_BAD_SIG; } // шаг 12: R <- sP + rQ - if (!ecAddMulA(x, ec, stack, 2, ec->base, s, order_n, x, r, order_n)) + if (!ecAddMulA(R, ec, stack, 2, ec->base, s, m, R, r, m)) { - dstuEcClose(ec); + blobClose(state); 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); + ASSERT(m <= ec->f->n); qrTo((octet*)s, y, ec->f, stack); - wwFrom(s, s, order_no); - wwTrimHi(s, order_n, order_nb - 1); + wwFrom(s, s, mo); + wwTrimHi(s, m, mb - 1); // шаг 15: - if (!wwEq(r, s, order_n)) - code = ERR_BAD_SIG; - // все нормально + code = wwEq(r, s, m) ? ERR_OK : ERR_BAD_SIG; + // завершение + blobClose(state); + 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; + ec_o* ec; + code = dstuEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = dstuVerifyEc(ec, ld, hash, hash_len, sig, pubkey); dstuEcClose(ec); return code; } diff --git a/src/crypto/g12s.c b/src/crypto/g12s.c index d19682ca..246f2866 100644 --- a/src/crypto/g12s.c +++ b/src/crypto/g12s.c @@ -4,7 +4,7 @@ \brief GOST R 34.10-94 (Russia): digital signature algorithms \project bee2 [cryptographic library] \created 2012.07.09 -\version 2025.05.07 +\version 2025.09.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -21,23 +21,6 @@ #include "bee2/math/ww.h" #include "bee2/math/zz.h" -/* -******************************************************************************* -Глубина стека - -Высокоуровневые функции сообщают о потребностях в стековой памяти через -функции интерфейса g12s_deep_i. Потребности не должны учитывать память для -размещения описаний базового поля и эллиптической кривой. -******************************************************************************* -*/ - -typedef size_t (*g12s_deep_i)( - size_t n, /* размерность (в машинных словах) */ - size_t f_deep, /* глубина стека базового поля */ - size_t ec_d, /* число проективных координат */ - size_t ec_deep /* глубина стека эллиптической кривой */ -); - /* ******************************************************************************* Стандартные параметры: проверочный пример A.1 из ГОСТ Р 34.10-2012 @@ -565,16 +548,13 @@ err_t g12sParamsStd(g12s_params* params, const char* name) /* ******************************************************************************* -Создание описания эллиптической кривой +Создание эллиптической кривой + +По долговременным параметрам params создается эллиптическая кривая. Указатель +на описание кривой возвращается по адресу pec. -По долговременным параметрам params формируется описание pec эллиптической -кривой. Указатель *pec является одновременно началом фрагмента памяти, -в котором размещается состояние и стек. Длина фрагмента определяется с учетом -потребностей deep и размерностей dims. \pre Указатель pec корректен. -\return ERR_OK, если описание успешно создано, и код ошибки в противном -случае. -\remark Запрошенная память начинается по адресу objEnd(*pec, void). +\return ERR_OK, если кривая успешно создана, и код ошибки в противном случае. \remark Проводится минимальная проверка параметров, обеспечивающая работоспособность высокоуровневых функций. \remark Диапазоны для q: @@ -582,61 +562,61 @@ err_t g12sParamsStd(g12s_params* params, const char* name) - 2^508 \leq q \leq 2^512 (l == 512). . \post Диапазоны для p: - |nq - (p + 1)| \leq 2\sqrt{p} => + |cofactor * q - (p + 1)| \leq 2\sqrt{p} => (\sqrt{nq} - 1)^2 \leq p \leq (\sqrt{nq} + 1)^2 => p \geq (\sqrt{q} - 1)^2 => p > 2^253 (l == 256) p > 2^507 (l == 512) В частности, длина p (в октетах, в словах) не меньше длины q. +\remark После создания эллиптической кривой ec уровень стойкости можно +определить по ec->f->no: ec->f->no < 64 <=> l == 256. ******************************************************************************* */ static err_t g12sEcCreate( - ec_o** pec, /* [out] описание эллиптической кривой */ - const g12s_params* params, /* [in] долговременные параметры */ - g12s_deep_i deep /* [in] потребности в стековой памяти */ + ec_o** pec, /* [out] эллиптическая кривая */ + const g12s_params* params /* [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; /* кривая */ + ec_o* ec; /* [ecpCreateJ_keep(n)] кривая */ + qr_o* f; /* [gfpCreate_keep(no)] базовое поле */ void* stack; - // pre - ASSERT(memIsValid(pec, sizeof(*pec))); - // минимальная проверка входных данных - if (!memIsValid(params, sizeof(g12s_params)) || - params->l != 256 && params->l != 512) + // входной контроль + if (!memIsValid(pec, sizeof(*pec)) || + !memIsValid(params, sizeof(g12s_params))) + return ERR_BAD_INPUT; + if (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))); + state = blobCreate2( + ecpCreateJ_keep(n), + gfpCreate_keep(no), + SIZE_MAX, + &ec, &f); if (state == 0) return ERR_OUTOFMEMORY; + // создать стек + stack = blobCreate( + utilMax(3, + gfpCreate_deep(no), + ecpCreateJ_deep(n, f_deep), + ecGroupCreate_deep(f_deep))); + if (stack == 0) + { + blobClose(state); + return ERR_OUTOFMEMORY; + } // создать поле - f = (qr_o*)((octet*)state + ec_keep); - stack = (octet*)f + f_keep; if (!gfpCreate(f, params->p, no, stack)) { + blobClose(stack); blobClose(state); return ERR_BAD_PARAMS; } @@ -645,15 +625,16 @@ static err_t g12sEcCreate( if (params->l == 256 && nb <= 253 || params->l == 512 && nb <= 507) { + blobClose(stack); 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, + !ecGroupCreate(ec, params->xP, params->yP, params->q, params->l / 8, params->n, stack)) { + blobClose(stack); blobClose(state); return ERR_BAD_PARAMS; } @@ -664,19 +645,21 @@ static err_t g12sEcCreate( params->l == 512 && nb <= 508 || zzIsEven(ec->order, n)) { + blobClose(stack); blobClose(state); return ERR_BAD_PARAMS; } // присоединить f к ec objAppend(ec, f, 0); - // все нормально + // завершить + blobClose(stack); *pec = ec; return ERR_OK; } /* ******************************************************************************* -Закрытие описания эллиптической кривой +Закрытие эллиптической кривой ******************************************************************************* */ @@ -692,48 +675,55 @@ static void g12sEcClose(ec_o* ec) -# l \in {256, 512} (g12sEcCreate) -# 2^254 < q < 2^256 или 2^508 < q < 2^512 (g12sEcCreate) -# p -- простое (ecpIsValid) --# q -- простое (ecpIsSafeGroup) --# q != p (ecpIsSafeGroup) --# p^m \not\equiv 1 (mod q), m = 1, 2,..., 31 или 131 (ecpIsSafeGroup) +-# q -- простое (ecpGroupIsSafe) +-# q != p (ecpGroupIsSafe) +-# p^m \not\equiv 1 (mod q), m = 1, 2,..., 31 или 131 (ecpGroupIsSafe) -# a, b < p (ecpCreateJ in g12sEcCreate) -# J(E) \notin {0, 1728} <=> a, b != 0 (g12sParamsVal) -# 4a^3 + 27b^2 \not\equiv 0 (\mod p) (ecpIsValid) --# P \in E (ecpSeemsValidGroup) --# |n * q - (p + 1)| \leq 2\sqrt{p} (ecpSeemsValidGroup) +-# P \in E (ecpGroupSeemsValid) +-# |cofactor * q - (p + 1)| \leq 2\sqrt{p} (ecpGroupSeemsValid) -# qP = O (ecpHasOrder) - ******************************************************************************* */ -static size_t g12sParamsVal_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +static err_t g12sParamsValEc(const ec_o* ec) { - return utilMax(4, - ecpIsValid_deep(n, f_deep), - ecpSeemsValidGroup_deep(n, f_deep), - ecpIsSafeGroup_deep(n), - ecHasOrderA_deep(n, ec_d, ec_deep, n)); -} - -err_t g12sParamsVal(const g12s_params* params) -{ - err_t code; - // состояние - ec_o* ec = 0; void* stack; - // старт - code = g12sEcCreate(&ec, params, g12sParamsVal_deep); - ERR_CALL_CHECK(code); - stack = objEnd(ec, void); + // pre + ASSERT(ecIsOperable(ec)); + // создать стек + stack = blobCreate( + utilMax(4, + ecpIsValid_deep(ec->f->n, ec->f->deep), + ecpGroupSeemsValid_deep(ec->f->n, ec->f->deep), + ecpGroupIsSafe_deep(ec->f->n), + ecHasOrderA_deep(ec->f->n, ec->d, ec->deep, ec->f->n))); + if (stack == 0) + return ERR_OUTOFMEMORY; // проверить кривую, проверить J(E) if (!ecpIsValid(ec, stack) || - !ecpSeemsValidGroup(ec, stack) || - !ecpIsSafeGroup(ec, params->l == 256 ? 31 : 131, stack) || + !ecpGroupSeemsValid(ec, stack) || + !ecpGroupIsSafe(ec, ec->f->no < 64 ? 31 : 131, stack) || !ecHasOrderA(ec->base, ec, ec->order, ec->f->n, stack) || - qrIsZero(ec->A, ec->f) || + qrIsZero(ec->A, ec->f) || qrIsZero(ec->B, ec->f)) - code = ERR_BAD_PARAMS; + { + blobClose(stack); + return ERR_BAD_PARAMS; + } // завершение + blobClose(stack); + return ERR_OK; +} + +err_t g12sParamsVal(const g12s_params* params) +{ + err_t code; + ec_o* ec; + code = g12sEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = g12sParamsValEc(ec); g12sEcClose(ec); return code; } @@ -744,127 +734,119 @@ err_t g12sParamsVal(const g12s_params* params) ******************************************************************************* */ -static size_t g12sKeypairGen_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) +static err_t g12sKeypairGenEc(octet privkey[], octet pubkey[], + const ec_o* ec, gen_i rng, void* rng_state) { - const size_t m = n; - return O_OF_W(m + 2 * n) + - ecMulA_deep(n, ec_d, ec_deep, n); -} - -err_t g12sKeypairGen(octet privkey[], octet pubkey[], - const g12s_params* params, gen_i rng, void* rng_stack) -{ - err_t code; size_t m, mo; - // состояние - ec_o* ec = 0; - word* d; /* [m] личный ключ */ - word* Q; /* [2n] открытый ключ */ + void* state; + word* d; /* [m] личный ключ */ + word* Q; /* [2 * n] открытый ключ */ void* stack; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // старт - code = g12sEcCreate(&ec, params, g12sKeypairGen_deep); - ERR_CALL_CHECK(code); - // размерности order - m = W_OF_B(params->l); - mo = O_OF_B(params->l); - // проверить входные указатели - if (!memIsValid(privkey, mo) || + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mo = ec->f->no < 64 ? 32 : 64; + m = W_OF_O(mo); + // входной контроль + if (!memIsValid(privkey, mo) || !memIsValid(pubkey, 2 * ec->f->no)) - { - g12sEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - d = objEnd(ec, word); - Q = d + m; - stack = Q + 2 * ec->f->n; + if (rng == 0) + return ERR_BAD_RNG; + // создать состояние + state = blobCreate2( + O_OF_W(m), + O_OF_W(2 * ec->f->n), + ecMulA_deep(ec->f->n, ec->d, ec->deep, m), + SIZE_MAX, + &d, &Q, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // d <-R {1,2,..., q - 1} - if (!zzRandNZMod(d, ec->order, m, rng, rng_stack)) + if (!zzRandNZMod(d, ec->order, m, rng, rng_state)) { - g12sEcClose(ec); + blobClose(state); return ERR_BAD_RNG; } // Q <- d P if (!ecMulA(Q, ec->base, ec, d, m, stack)) { - g12sEcClose(ec); + blobClose(state); 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); - // все нормально - g12sEcClose(ec); + // завершение + blobClose(state); return ERR_OK; } +err_t g12sKeypairGen(octet privkey[], octet pubkey[], + const g12s_params* params, gen_i rng, void* rng_state) +{ + err_t code; + ec_o* ec; + code = g12sEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = g12sKeypairGenEc(privkey, pubkey, ec, rng, rng_state); + g12sEcClose(ec); + return code; +} + /* ******************************************************************************* Выработка ЭЦП ******************************************************************************* */ -static size_t g12sSign_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - const size_t m = n; - return O_OF_W(3 * m + 2 * n) + - utilMax(3, - zzMod_deep(m, m), - ecMulA_deep(n, ec_d, ec_deep, n), - zzMulMod_deep(m)); -} - -err_t g12sSign(octet sig[], const g12s_params* params, const octet hash[], - const octet privkey[], gen_i rng, void* rng_stack) +static err_t g12sSignEc(octet sig[], const ec_o* ec, const octet hash[], + const octet privkey[], gen_i rng, void* rng_state) { - err_t code; size_t m, mo; - // состояние - ec_o* ec = 0; + void* state; word* d; /* [m] личный ключ */ word* e; /* [m] обработанное хэш-значение */ word* k; /* [m] одноразовый ключ */ - word* C; /* [2n] вспомогательная точка */ + word* C; /* [2 * n] вспомогательная точка */ word* r; /* [m] первая (старшая) часть подписи */ word* s; /* [m] вторая часть подписи */ void* stack; - // проверить rng - if (rng == 0) - return ERR_BAD_RNG; - // старт - code = g12sEcCreate(&ec, params, g12sSign_deep); - ERR_CALL_CHECK(code); - // размерности order - m = W_OF_B(params->l); - mo = O_OF_B(params->l); - // проверить входные указатели + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mo = ec->f->no < 64 ? 32 : 64; + m = W_OF_O(mo); + // входной контроль if (!memIsValid(hash, mo) || !memIsValid(privkey, mo) || !memIsValid(sig, 2 * mo)) - { - g12sEcClose(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; + if (rng == 0) + return ERR_BAD_RNG; + // создать состояние + state = blobCreate2( + O_OF_W(m), + O_OF_W(m), + O_OF_W(m), + O_OF_W(2 * ec->f->n), + O_OF_W(m), + O_OF_W(m), + utilMax(3, + zzMod_deep(m, m), + ecMulA_deep(ec->f->n, ec->d, ec->deep, ec->f->n), + zzMulMod_deep(m)), + SIZE_MAX, + &d, &e, &k, &C, &r, &s, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // загрузить d wwFrom(d, privkey, mo); - if (wwIsZero(d, m) || + if (wwIsZero(d, m) || wwCmp(d, ec->order, m) >= 0) { - g12sEcClose(ec); + blobClose(state); return ERR_BAD_PRIVKEY; } // e <- hash \mod q @@ -877,17 +859,17 @@ err_t g12sSign(octet sig[], const g12s_params* params, const octet hash[], e[0] = 1; // k <-R {1,2,..., q - 1} gen_k: - if (!zzRandNZMod(k, ec->order, m, rng, rng_stack)) + if (!zzRandNZMod(k, ec->order, m, rng, rng_state)) { - g12sEcClose(ec); + blobClose(state); return ERR_BAD_RNG; } // C <- k P if (!ecMulA(C, ec->base, ec, k, m, stack)) { + blobClose(state); // если params корректны, то этого быть не должно - g12sEcClose(ec); - return ERR_BAD_INPUT; + return ERR_BAD_PARAMS; } // r <- x_C \mod q qrTo((octet*)C, ecX(C), ec->f, stack); @@ -904,68 +886,69 @@ err_t g12sSign(octet sig[], const g12s_params* params, const octet hash[], wwTo(sig, mo, s); wwTo(sig + mo, mo, r); memRev(sig, 2 * mo); - // все нормально - g12sEcClose(ec); + // завершение + blobClose(state); return ERR_OK; } +err_t g12sSign(octet sig[], const g12s_params* params, const octet hash[], + const octet privkey[], gen_i rng, void* rng_state) +{ + err_t code; + ec_o* ec; + code = g12sEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = g12sSignEc(sig, ec, hash, privkey, rng, rng_state); + g12sEcClose(ec); + return code; +} + /* ******************************************************************************* Проверка ЭЦП ******************************************************************************* */ -static size_t g12sVerify_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - const size_t m = n; - return O_OF_W(5 * m + 2 * n) + - utilMax(4, - zzMod_deep(m, m), - zzMulMod_deep(m), - zzInvMod_deep(m), - ecAddMulA_deep(n, ec_d, ec_deep, 2, m, m)); -} - -err_t g12sVerify(const g12s_params* params, const octet hash[], +static err_t g12sVerifyEc(const ec_o* ec, const octet hash[], const octet sig[], const octet pubkey[]) { err_t code; size_t m, mo; - // состояние - ec_o* ec = 0; - word* Q; /* [2n] открытый ключ / точка R */ + void* state; + word* Q; /* [2 * n] открытый ключ / точка R */ word* r; /* [m] первая (старшая) часть подписи */ word* s; /* [m] вторая часть подписи */ word* e; /* [m] обработанное хэш-значение, v */ void* stack; - // старт - code = g12sEcCreate(&ec, params, g12sVerify_deep); - ERR_CALL_CHECK(code); - // размерности order - m = W_OF_B(params->l); - mo = O_OF_B(params->l); - // проверить входные указатели + // pre + ASSERT(ecIsOperable(ec)); + // размерности + mo = ec->f->no < 64 ? 32 : 64; + m = W_OF_O(mo); + // входной контроль if (!memIsValid(hash, mo) || !memIsValid(sig, 2 * mo) || !memIsValid(pubkey, 2 * ec->f->no)) - { - g12sEcClose(ec); return ERR_BAD_INPUT; - } - // раскладка состояния - Q = objEnd(ec, word); - r = Q + 2 * ec->f->n; - s = r + m; - e = s + m; - stack = e + m; + // создать состояние + state = blobCreate2( + O_OF_W(2 * ec->f->n), + O_OF_W(m), + O_OF_W(m), + O_OF_W(m), + utilMax(4, + zzMod_deep(m, m), + zzMulMod_deep(m), + zzInvMod_deep(m), + ecAddMulA_deep(ec->f->n, ec->d, ec->deep, 2, m, m)), + SIZE_MAX, + &Q, &r, &s, &e, &stack); + if (state == 0) + return ERR_OUTOFMEMORY; // загрузить Q if (!qrFrom(ecX(Q), pubkey, ec->f, stack) || !qrFrom(ecY(Q, ec->f->n), pubkey + ec->f->no, ec->f, stack)) - { - g12sEcClose(ec); return ERR_BAD_PUBKEY; - } // загрузить r и s memCopy(s, sig + mo, mo); memRev(s, mo); @@ -977,10 +960,7 @@ err_t g12sVerify(const g12s_params* params, const octet hash[], wwIsZero(r, m) || wwCmp(s, ec->order, m) >= 0 || wwCmp(r, ec->order, m) >= 0) - { - g12sEcClose(ec); return ERR_BAD_SIG; - } // e <- hash \mod q memCopy(e, hash, mo); memRev(e, mo); @@ -998,17 +978,25 @@ err_t g12sVerify(const g12s_params* params, const octet hash[], 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)) - { - g12sEcClose(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; - // завершение + blobClose(state); + return code; +} + +err_t g12sVerify(const g12s_params* params, const octet hash[], + const octet sig[], const octet pubkey[]) +{ + err_t code; + ec_o* ec; + code = g12sEcCreate(&ec, params); + ERR_CALL_CHECK(code); + code = g12sVerifyEc(ec, hash, sig, pubkey); g12sEcClose(ec); return code; } diff --git a/src/crypto/pfok.c b/src/crypto/pfok.c index 935ca2fc..f86a0f49 100644 --- a/src/crypto/pfok.c +++ b/src/crypto/pfok.c @@ -4,7 +4,7 @@ \brief Draft of RD_RB: key establishment protocols in finite fields \project bee2 [cryptographic library] \created 2014.07.01 -\version 2025.06.11 +\version 2025.09.15 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -588,11 +588,11 @@ err_t pfokParamsGen(pfok_params* params, const pfok_seed* seed, size_t base_count; // состояние void* state; - octet* stb_state; - word* qi; - word* p; - word* g; - qr_o* qr; + octet* stb_state; /* [prngSTB_keep()] */ + word* qi; /* [qw] */ + word* p; /* [n] */ + word* g; /* [n] */ + qr_o* qr; /* [zmMontCreate_keep(no)] кольцо Монтгомери */ void* stack; // проверить seed code = pfokSeedVal(seed); @@ -617,8 +617,12 @@ err_t pfokParamsGen(pfok_params* params, const pfok_seed* seed, n = W_OF_B(params->l), no = O_OF_B(params->l); ASSERT(W_OF_B(seed->li[0]) == n); // создать состояние - state = blobCreate( - prngSTB_keep() + O_OF_W(qw + 2 * n) + zmMontCreate_keep(no) + + state = blobCreate2( + prngSTB_keep(), + O_OF_W(qw), + O_OF_W(n), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(6, priNextPrimeW_deep(), priExtendPrime_deep(params->l, W_OF_B(seed->li[1]), @@ -626,16 +630,11 @@ err_t pfokParamsGen(pfok_params* params, const pfok_seed* seed, priIsSieved_deep((seed->li[0] + 3) / 4), priIsSGPrime_deep(n), zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &stb_state, &qi, &p, &g, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - stb_state = (octet*)state; - qi = (word*)(stb_state + prngSTB_keep()); - p = qi + qw; - g = p + n; - qr = (qr_o*)(g + n); - stack = (octet*)qr + zmMontCreate_keep(no); // запустить генератор prngSTBStart(stb_state, seed->zi); // основной цикл @@ -723,10 +722,10 @@ err_t pfokParamsVal(const pfok_params* params) size_t n, no; // состояние void* state; - word* p; - word* q; - word* g; - qr_o* qr; + word* p; /* [n] */ + word* q; /* [n] */ + word* g; /* [n] */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить указатели if (!memIsValid(params, sizeof(pfok_params))) @@ -737,19 +736,18 @@ err_t pfokParamsVal(const pfok_params* params) // размерности no = O_OF_B(params->l), n = W_OF_B(params->l); // создать состояние - state = blobCreate( - O_OF_W(2 * n) + zmMontCreate_keep(no) + - utilMax(3, + state = blobCreate2( + O_OF_W(n), + O_OF_W(n), + zmMontCreate_keep(no), + utilMax(3, priIsPrime_deep(n), zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &p, &g, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - p = (word*)state; - g = p + n; - qr = (qr_o*)(g + n); - stack = (octet*)qr + zmMontCreate_keep(no); // p -- простое? wwFrom(p, params->p, no); if (!priIsPrime(p, n, stack)) @@ -795,7 +793,7 @@ err_t pfokKeypairGen(octet privkey[], octet pubkey[], void* state; word* x; /* [m] личный ключ */ word* y; /* [n] открытый ключ */ - qr_o* qr; /* описание кольца Монтгомери */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить params if (!memIsValid(params, sizeof(pfok_params))) @@ -810,18 +808,17 @@ err_t pfokKeypairGen(octet privkey[], octet pubkey[], if (!memIsValid(privkey, mo) || !memIsValid(pubkey, no) || rng == 0) return ERR_BAD_INPUT; // создать состояние - state = blobCreate( - O_OF_W(n) + O_OF_W(m) + zmMontCreate_keep(no) + + state = blobCreate2( + O_OF_W(m), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(2, zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &x, &y, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - x = (word*)state; - y = x + m; - qr = (qr_o*)(y + n); - stack = (octet*)qr + zmMontCreate_keep(no); // построить кольцо Монтгомери zmMontCreate(qr, params->p, no, params->l + 2, stack); // x <-R {0, 1,..., 2^r - 1} @@ -869,7 +866,7 @@ err_t pfokPubkeyCalc(octet pubkey[], const pfok_params* params, void* state; word* x; /* [m] личный ключ */ word* y; /* [n] открытый ключ */ - qr_o* qr; /* описание кольца Монтгомери */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить params if (!memIsValid(params, sizeof(pfok_params))) @@ -884,18 +881,17 @@ err_t pfokPubkeyCalc(octet pubkey[], const pfok_params* params, if (!memIsValid(privkey, mo) || !memIsValid(pubkey, no)) return ERR_BAD_INPUT; // создать состояние - state = blobCreate( - O_OF_W(n) + O_OF_W(m) + zmMontCreate_keep(no) + + state = blobCreate2( + O_OF_W(m), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(2, zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &x, &y, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - x = (word*)state; - y = x + m; - qr = (qr_o*)(y + n); - stack = (octet*)qr + zmMontCreate_keep(no); // построить кольцо Монтгомери zmMontCreate(qr, params->p, no, params->l + 2, stack); // x <- privkey @@ -930,7 +926,7 @@ err_t pfokDH(octet sharekey[], const pfok_params* params, void* state; word* x; /* [m] личный ключ */ word* y; /* [n] открытый ключ визави */ - qr_o* qr; /* описание кольца Монтгомери */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить params if (!memIsValid(params, sizeof(pfok_params))) @@ -947,18 +943,17 @@ err_t pfokDH(octet sharekey[], const pfok_params* params, !memIsValid(sharekey, O_OF_B(params->n))) return ERR_BAD_INPUT; // создать состояние - state = blobCreate( - O_OF_W(n) + O_OF_W(m) + zmMontCreate_keep(no) + + state = blobCreate2( + O_OF_W(m), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(2, zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &x, &y, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - x = (word*)state; - y = x + m; - qr = (qr_o*)(y + n); - stack = (octet*)qr + zmMontCreate_keep(no); // построить кольцо Монтгомери zmMontCreate(qr, params->p, no, params->l + 2, stack); // x <- privkey @@ -998,7 +993,7 @@ err_t pfokMTI(octet sharekey[], const pfok_params* params, word* u; /* [m] одноразовый личный ключ */ word* y; /* [n] открытый ключ визави */ word* v; /* [n] одноразовый открытый ключ визави */ - qr_o* qr; /* описание кольца Монтгомери */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить params if (!memIsValid(params, sizeof(pfok_params))) @@ -1017,20 +1012,19 @@ err_t pfokMTI(octet sharekey[], const pfok_params* params, !memIsValid(sharekey, O_OF_B(params->n))) return ERR_BAD_INPUT; // создать состояние - state = blobCreate( - 2 * O_OF_W(n) + 2 * O_OF_W(m) + zmMontCreate_keep(no) + + state = blobCreate2( + O_OF_W(m), + O_OF_W(m), + O_OF_W(n), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(2, zmMontCreate_deep(no), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &x, &u, &y, &v, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - x = (word*)state; - u = x + m; - y = u + m; - v = y + n; - qr = (qr_o*)(v + n); - stack = (octet*)qr + zmMontCreate_keep(no); // построить кольцо Монтгомери zmMontCreate(qr, params->p, no, params->l + 2, stack); // x <- privkey, u <- privkey1 diff --git a/src/crypto/stb99.c b/src/crypto/stb99.c index 110c9447..09b813ef 100644 --- a/src/crypto/stb99.c +++ b/src/crypto/stb99.c @@ -4,7 +4,7 @@ \brief STB 1176.2-99: generation of parameters \project bee2 [cryptographic library] \created 2023.08.01 -\version 2024.02.29 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -628,14 +628,14 @@ err_t stb99ParamsGen(stb99_params* params, const stb99_seed* seed) size_t base_count; // состояние void* state; - octet* stb_state; - word* gi; /* промежуточные простые при построении g0 */ - word* fi; /* промежуточные простые при построении q */ - word* g0; - word* p; - word* d; - word* a; - qr_o* qr; + octet* stb_state; /* [prngSTB_keep()] */ + word* gi; /* [gw] промежуточные простые для g0 */ + word* fi; /* [gw] промежуточные простые для q (|gi) */ + word* g0; /* [gw] (|gi) */ + word* p; /* [seed->di[0]] */ + word* d; /* [n] */ + word* a; /* [n] */ + qr_o* qr; /* [zmMontCreate_deep(no)] кольцо Монтгомери */ void* stack; // проверить seed code = stb99SeedVal(seed); @@ -668,9 +668,15 @@ err_t stb99ParamsGen(stb99_params* params, const stb99_seed* seed) m = W_OF_B(params->r), mo = O_OF_B(params->r); ASSERT(n <= gw); // создать состояние - state = blobCreate( - prngSTB_keep() + O_OF_W(gw) + - O_OF_W(W_OF_B(seed->di[0]) + 2 * n) + zmMontCreate_keep(no) + + state = blobCreate2( + prngSTB_keep(), + O_OF_W(gw), + O_OF_W(gw) | SIZE_HI, + O_OF_W(gw) | SIZE_HI, + O_OF_W(W_OF_B(seed->di[0])), + O_OF_W(n), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(6, priNextPrimeW_deep(), priExtendPrime_deep(params->l, W_OF_B(seed->di[1]), @@ -679,17 +685,11 @@ err_t stb99ParamsGen(stb99_params* params, const stb99_seed* seed) W_OF_B(seed->ri[0]), (params->l + 3) / 4), zmMontCreate_deep(no), zzDiv_deep(n, m), - qrPower_deep(n, n, zmMontCreate_deep(no)))); + qrPower_deep(n, n, zmMontCreate_deep(no))), + SIZE_MAX, + &stb_state, &fi, &gi, &d, &g0, &p, &a, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - stb_state = (octet*)state; - fi = gi = d = (word*)(stb_state + prngSTB_keep()); - g0 = gi + gw; - p = g0 + W_OF_B(seed->di[0]); - a = p + n; - qr = (qr_o*)(a + n); - stack = (octet*)qr + zmMontCreate_keep(no); // запустить генератор prngSTBStart(stb_state, seed->zi); // построить цепочку gi @@ -833,12 +833,12 @@ err_t stb99ParamsVal(const stb99_params* params) size_t m, mo; // состояние void* state; - word* p; - word* q; - word* t; - word* d; - word* a; - qr_o* qr; + word* p; /* [n] */ + word* q; /* [n] (|p) */ + word* t; /* [n] */ + word* d; /* [m] */ + word* a; /* [n - m + 1] */ + qr_o* qr; /* [zmMontCreate_keep(no)] */ void* stack; // проверить указатели if (!memIsValid(params, sizeof(stb99_params))) @@ -853,22 +853,22 @@ err_t stb99ParamsVal(const stb99_params* params) n = W_OF_B(params->l), no = O_OF_B(params->l); m = W_OF_B(params->r), mo = O_OF_B(params->r); // создать состояние - state = blobCreate( - O_OF_W(3 * n + 1) + zmMontCreate_keep(no) + + state = blobCreate2( + O_OF_W(n), + O_OF_W(n) | SIZE_HI, + O_OF_W(m), + O_OF_W(n - m + 1), + O_OF_W(n), + zmMontCreate_keep(no), utilMax(4, priIsPrime_deep(n), zzDiv_deep(n, m), zmMontCreate_deep(no), - qrPower_deep(n, n - m + 1, zmMontCreate_deep(no)))); + qrPower_deep(n, n - m + 1, zmMontCreate_deep(no))), + SIZE_MAX, + &p, &d, &q, &t, &a, &qr, &stack); if (state == 0) return ERR_OUTOFMEMORY; - // раскладка состояния - p = d = (word*)state; - q = p + n; - t = q + m; - a = t + n - m + 1; - qr = (qr_o*)(a + n); - stack = (octet*)qr + zmMontCreate_keep(no); // p -- l-битовое простое? wwFrom(p, params->p, no); if (!memIsZero(params->p + no, sizeof(params->p) - no) || diff --git a/src/math/ec.c b/src/math/ec.c index a4b0464f..4a69b110 100644 --- a/src/math/ec.c +++ b/src/math/ec.c @@ -4,7 +4,7 @@ \brief Elliptic curves \project bee2 [cryptographic library] \created 2014.03.04 -\version 2025.06.10 +\version 2025.09.13 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -50,7 +50,7 @@ bool_t ecIsOperable(const ec_o* ec) ec->deep >= ec->f->deep; } -bool_t ecCreateGroup(ec_o* ec, const octet xbase[], const octet ybase[], +bool_t ecGroupCreate(ec_o* ec, const octet xbase[], const octet ybase[], const octet order[], size_t order_len, u32 cofactor, void* stack) { ASSERT(ecIsOperable(ec)); @@ -82,12 +82,12 @@ bool_t ecCreateGroup(ec_o* ec, const octet xbase[], const octet ybase[], return TRUE; } -size_t ecCreateGroup_deep(size_t f_deep) +size_t ecGroupCreate_deep(size_t f_deep) { return f_deep; } -bool_t ecIsOperableGroup(const ec_o* ec) +bool_t ecGroupIsOperable(const ec_o* ec) { ASSERT(ecIsOperable(ec)); return wwIsValid(ec->base, 2 * ec->f->n) && @@ -163,6 +163,11 @@ static size_t ecNAFWidth(size_t l) return 3; } +#define ecMulA_local(n, ec_d, m, naf_count)\ +/* naf */ O_OF_W(2 * m + 1),\ +/* t */ O_OF_W(ec_d * n),\ +/* pre */ O_OF_W(naf_count * ec_d * n) + bool_t ecMulA(word b[], const word a[], const ec_o* ec, const word d[], size_t m, void* stack) { @@ -173,17 +178,15 @@ bool_t ecMulA(word b[], const word a[], const ec_o* ec, const word d[], register size_t naf_size; register size_t i; register word w; - // переменные в stack - word* naf; /* NAF */ - word* t; /* вспомогательная точка */ - word* pre; /* pre[i] = (2i + 1)a (naf_count элементов) */ + word* naf; /* [2 * m + 1] NAF */ + word* t; /* [ec->d * n] вспомогательная точка */ + word* pre; /* [naf_count * ec->d * n] pre[i] = (2i + 1)a */ // pre ASSERT(ecIsOperable(ec)); - // раскладка stack - naf = (word*)stack; - t = naf + 2 * m + 1; - pre = t + ec->d * n; - stack = pre + naf_count * ec->d * n; + // разметить стек + memSlice(stack, + ecMulA_local(n, ec->d, m, naf_count), SIZE_0, SIZE_MAX, + &naf, &t, &pre, &stack); // расчет NAF ASSERT(naf_width >= 3); naf_size = wwNAF(naf, d, m, naf_width); @@ -236,10 +239,10 @@ size_t ecMulA_deep(size_t n, size_t ec_d, size_t ec_deep, size_t m) { const size_t naf_width = ecNAFWidth(B_OF_W(m)); const size_t naf_count = SIZE_1 << (naf_width - 2); - return O_OF_W(2 * m + 1) + - O_OF_W(ec_d * n) + - O_OF_W(ec_d * n * naf_count) + - ec_deep; + return memSliceSize( + ecMulA_local(n, ec_d, m, naf_count), + ec_deep, + SIZE_MAX); } /* @@ -248,20 +251,28 @@ size_t ecMulA_deep(size_t n, size_t ec_d, size_t ec_deep, size_t m) ******************************************************************************* */ +#define ecHasOrderA_local(n, ec_d)\ +/* b */ O_OF_W(ec_d * n) + bool_t ecHasOrderA(const word a[], const ec_o* ec, const word q[], size_t m, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* b = (word*)stack; - stack = b + ec->d * n; + word* b; /* [ec->d * n] */ + // разметить стек + memSlice(stack, + ecHasOrderA_local(n, ec->d), SIZE_0, SIZE_MAX, + &b, &stack); // q a == O? return !ecMulA(b, a, ec, q, m, stack); } size_t ecHasOrderA_deep(size_t n, size_t ec_d, size_t ec_deep, size_t m) { - return O_OF_W(ec_d * n) + ecMulA_deep(n, ec_d, ec_deep, m); + return memSliceSize( + ecHasOrderA_local(n, ec_d), + ecMulA_deep(n, ec_d, ec_deep, m), + SIZE_MAX); } /* @@ -279,59 +290,62 @@ Elliptic Curve Cryptography, Springer, 2004] (interleaving with NAF). ******************************************************************************* */ +#define ecAddMulA_local(n, ec_d)\ +/* t */ O_OF_W(ec_d * n),\ +/* m */ O_PER_S * k,\ +/* naf_width */ O_PER_S * k,\ +/* naf_size */ O_PER_S * k,\ +/* naf_pos */ O_PER_S * k,\ +/* naf */ sizeof(word*) * k,\ +/* pre */ sizeof(word*) * k + bool_t ecAddMulA(word b[], const ec_o* ec, void* stack, size_t k, ...) { const size_t n = ec->f->n; register word w; size_t i, naf_max_size = 0; - va_list marker; - // переменные в stack - word* t; /* проективная точка */ - size_t* m; /* длины d[i] */ - size_t* naf_width; /* размеры NAF-окон */ - size_t* naf_size; /* длины NAF */ - size_t* naf_pos; /* позиция в NAF-представлении */ - word** naf; /* NAF */ - word** pre; /* предвычисленные точки */ + va_list args; + word* t; /* [ec->d * n] проективная точка */ + size_t* m; /* [k] длины d[i] */ + size_t* naf_width; /* [k] размеры NAF-окон */ + size_t* naf_size; /* [k] длины NAF */ + size_t* naf_pos; /* [k] позиция в NAF-представлении */ + word** naf; /* [k] NAF */ + word** pre; /* [k] предвычисленные точки */ // pre ASSERT(ecIsOperable(ec)); ASSERT(k > 0); - // раскладка stack - t = (word*)stack; - m = (size_t*)(t + ec->d * n); - naf_width = m + k; - naf_size = naf_width + k; - naf_pos = naf_size + k; - naf = (word**)(naf_pos + k); - pre = naf + k; - stack = pre + k; + // разметить стек + memSlice(stack, + ecAddMulA_local(n, ec->d), SIZE_0, SIZE_MAX, + &t, &m, &naf_width, &naf_size, &naf_pos, &naf, &pre, &stack); // обработать параметры (a[i], d[i], m[i]) - va_start(marker, k); + va_start(args, k); for (i = 0; i < k; ++i) { const word* a; const word* d; size_t naf_count, j; // a <- a[i] - a = va_arg(marker, const word*); + a = va_arg(args, const word*); // d <- d[i] - d = va_arg(marker, const word*); + d = va_arg(args, const word*); // прочитать m[i] - m[i] = va_arg(marker, size_t); + m[i] = va_arg(args, size_t); // подправить m[i] m[i] = wwWordSize(d, m[i]); - // расчет naf[i] + // зарезервировать память для naf[i] и pre[i] naf_width[i] = ecNAFWidth(B_OF_W(m[i])); naf_count = SIZE_1 << (naf_width[i] - 2); - naf[i] = (word*)stack; - stack = naf[i] + 2 * m[i] + 1; + memSlice(stack, + O_OF_W(2 * m[i] + 1), O_OF_W(ec->d * n * naf_count), SIZE_0, + SIZE_MAX, + naf + i, pre + i, &stack); + // расчет naf[i] naf_size[i] = wwNAF(naf[i], d, m[i], naf_width[i]); if (naf_size[i] > naf_max_size) naf_max_size = naf_size[i]; naf_pos[i] = 0; - // резервируем память для pre[i] - pre[i] = (word*)stack; - stack = pre[i] + ec->d * n * naf_count; // pre[i][0] <- a[i] ecFromA(pre[i], a, ec, stack); // расчет pre[i][j]: t <- 2a[i], pre[i][j] <- t + pre[i][j - 1] @@ -342,7 +356,7 @@ bool_t ecAddMulA(word b[], const ec_o* ec, void* stack, size_t k, ...) ecAdd(pre[i] + j * ec->d * n, t, pre[i] + (j - 1) * ec->d * n, ec, stack); } - va_end(marker); + va_end(args); // t <- O ecSetO(t, ec); // основной цикл @@ -389,20 +403,21 @@ bool_t ecAddMulA(word b[], const ec_o* ec, void* stack, size_t k, ...) size_t ecAddMulA_deep(size_t n, size_t ec_d, size_t ec_deep, size_t k, ...) { size_t i, ret; - va_list marker; - ret = O_OF_W(ec_d * n); - ret += 4 * sizeof(size_t) * k; - ret += 2 * sizeof(word**) * k; - va_start(marker, k); + va_list args; + ret = memSliceSize( + ecAddMulA_local(n, ec_d), SIZE_0, SIZE_MAX); + va_start(args, k); for (i = 0; i < k; ++i) { - size_t m = va_arg(marker, size_t); + size_t m = va_arg(args, size_t); size_t naf_width = ecNAFWidth(B_OF_W(m)); size_t naf_count = SIZE_1 << (naf_width - 2); - ret += O_OF_W(2 * m + 1); - ret += O_OF_W(ec_d * n * naf_count); + ret += memSliceSize( + O_OF_W(2 * m + 1), + O_OF_W(ec_d * n * naf_count), + SIZE_0, SIZE_MAX); } - va_end(marker); + va_end(args); ret += ec_deep; return ret; } diff --git a/src/math/ec2.c b/src/math/ec2.c index 6240d824..5da7fd92 100644 --- a/src/math/ec2.c +++ b/src/math/ec2.c @@ -4,7 +4,7 @@ \brief Elliptic curves over binary fields \project bee2 [cryptographic library] \created 2012.06.26 -\version 2025.04.25 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -135,17 +135,22 @@ static bool_t ec2FromALD(word b[], const word a[], const ec_o* ec, return TRUE; } +#define ec2ToALD_local(n)\ +/* t1 */ O_OF_W(n) + // [2n]b <- [3n]a (A <- P) static bool_t ec2ToALD(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - stack = t1 + n; + word* t1; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(a == b || wwIsDisjoint2(a, 3 * n, b, 2 * n)); + // разметить стек + memSlice(stack, + ec2ToALD_local(n), SIZE_0, SIZE_MAX, + &t1, &stack); // a == O => b <- O if (qrIsZero(ecZ(a, n), ec->f)) return FALSE; @@ -163,20 +168,28 @@ static bool_t ec2ToALD(word b[], const word a[], const ec_o* ec, void* stack) static size_t ec2ToALD_deep(size_t n, size_t f_deep) { - return O_OF_W(n) + f_deep; + return memSliceSize( + ec2ToALD_local(n), + f_deep, + SIZE_MAX); } +#define ec2NegLD_local(n)\ +/* t1 */ O_OF_W(n) + // [3n]b <- -[3n]a (P <- -P) static void ec2NegLD(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - stack = t1 + n; + word* t1; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ec2NegLD_local(n), SIZE_0, SIZE_MAX, + &t1, &stack); // t1 <- xa * za qrMul(t1, ecX(a), ecZ(a, n), ec->f, stack); // b <- (xa, ya + t1, za) @@ -186,21 +199,30 @@ static void ec2NegLD(word b[], const word a[], const ec_o* ec, void* stack) static size_t ec2NegLD_deep(size_t n, size_t f_deep) { - return O_OF_W(n) + f_deep; + return memSliceSize( + ec2NegLD_local(n), + f_deep, + SIZE_MAX); } +#define ec2DblLD_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + // [3n]b <- 2[3n]a (P <- 2P) static void ec2DblLD(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ec2DblLD_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // za == 0 или xa == 0? => b <- O if (qrIsZero(ecZ(a, n), ec->f) || qrIsZero(ecX(a), ec->f)) { @@ -241,20 +263,28 @@ static void ec2DblLD(word b[], const word a[], const ec_o* ec, void* stack) static size_t ec2DblLD_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ec2DblLD_local(n), + f_deep, + SIZE_MAX); } +#define ec2DblALD_local(n)\ +/* t1 */ O_OF_W(n) + // [3n]b <- 2[2n]a (P <- 2A) static void ec2DblALD(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - stack = t1 + n; + word* t1; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOnA(a, ec)); ASSERT(a == b || wwIsDisjoint2(a, 2 * n, b, 3 * n)); + // разметить стек + memSlice(stack, + ec2DblALD_local(n), SIZE_0, SIZE_MAX, + &t1, &stack); // xa == 0? => b <- O if (qrIsZero(ecX(a), ec->f)) { @@ -287,28 +317,41 @@ static void ec2DblALD(word b[], const word a[], const ec_o* ec, void* stack) static size_t ec2DblALD_deep(size_t n, size_t f_deep) { - return O_OF_W(n) + f_deep; + return memSliceSize( + ec2DblALD_local(n), + f_deep, + SIZE_MAX); } +#define ec2AddLD_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n),\ +/* t5 */ O_OF_W(n),\ +/* t6 */ O_OF_W(n) + // [3n]c <- [3n]a + [3n]b (P <- P + P) static void ec2AddLD(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - word* t5 = t4 + n; - word* t6 = t5 + n; - stack = t6 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ + word* t5; /* [n] */ + word* t6; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(ec2SeemsOn3(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(wwIsSameOrDisjoint(b, c, 3 * n)); + // разметить стек + memSlice(stack, + ec2AddLD_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &t5, &t6, &stack); // a == O => c <- b if (qrIsZero(ecZ(a, n), ec->f)) { @@ -380,29 +423,39 @@ static void ec2AddLD(word c[], const word a[], const word b[], static size_t ec2AddLD_deep(size_t n, size_t f_deep) { - return O_OF_W(6 * n) + + return memSliceSize( + ec2AddLD_local(n), utilMax(2, f_deep, - ec2DblLD_deep(n, f_deep)); + ec2DblLD_deep(n, f_deep)), + SIZE_MAX); } +#define ec2AddALD_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n) + // [3n]c <- [3n]a + [2n]b (P <- P + A) static void ec2AddALD(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - stack = t4 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(ec2SeemsOnA(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n)); + // разметить стек + memSlice(stack, + ec2AddALD_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &stack); // a == O => c <- (xb : yb : 1) if (qrIsZero(ecZ(a, n), ec->f)) { @@ -467,26 +520,33 @@ static void ec2AddALD(word c[], const word a[], const word b[], static size_t ec2AddALD_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n) + + return memSliceSize( + ec2AddALD_local(n), utilMax(2, f_deep, - ec2DblALD_deep(n, f_deep)); + ec2DblALD_deep(n, f_deep)), + SIZE_MAX); } +#define ec2SubLD_local(n)\ +/* t */ O_OF_W(3 * n) + // [3n]c <- [3n]a - [3n]b (P <- P - P) static void ec2SubLD(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t = (word*)stack; - stack = t + 3 * n; + word* t; /* [3n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(ec2SeemsOn3(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(wwIsSameOrDisjoint(b, c, 3 * n)); + // разметить стек + memSlice(stack, + ec2SubLD_local(n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- -b qrMul(ecY(t, n), ecX(b), ecZ(b, n), ec->f, stack); gf2Add2(ecY(t, n), ecY(b, n), ec->f); @@ -498,26 +558,33 @@ static void ec2SubLD(word c[], const word a[], const word b[], static size_t ec2SubLD_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + + return memSliceSize( + ec2SubLD_local(n), utilMax(2, f_deep, - ec2AddLD_deep(n, f_deep)); + ec2AddLD_deep(n, f_deep)), + SIZE_MAX); } +#define ec2SubALD_local(n)\ +/* t */ O_OF_W(2 * n) + // [3n]c <- [3n]a - [2n]b (P <- P - A) static void ec2SubALD(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t = (word*)stack; - stack = t + 2 * n; + word* t; /* [2 * n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ec2SeemsOn3(a, ec)); ASSERT(ec2SeemsOnA(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n)); + // разметить стек + memSlice(stack, + ec2SubALD_local(n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- -b wwCopy(t, b, 2 * n); gf2Add2(ecY(t, n), ecX(t), ec->f); @@ -527,9 +594,19 @@ static void ec2SubALD(word c[], const word a[], const word b[], static size_t ec2SubALD_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + ec2AddALD_deep(n, f_deep); + return memSliceSize( + ec2SubALD_local(n), + ec2AddALD_deep(n, f_deep), + SIZE_MAX); } +#define ec2CreateLD_state(n)\ +/* A */ O_OF_W(n),\ +/* B */ O_OF_W(n),\ +/* base */ O_OF_W(2 * n),\ +/* order */ O_OF_W(n + 1),\ +/* params */ SIZE_0 + bool_t ec2CreateLD(ec_o* ec, const qr_o* f, const octet A[], const octet B[], void* stack) { @@ -539,18 +616,17 @@ bool_t ec2CreateLD(ec_o* ec, const qr_o* f, const octet A[], const octet B[], ASSERT(memIsValid(B, f->no)); // обнулить memSetZero(ec, sizeof(ec_o)); - // зафикисровать размерности + // зафиксировать размерности ec->d = 3; // запомнить базовое поле ec->f = f; + // разметить состояние + memSlice(ec->descr, + ec2CreateLD_state(f->n), SIZE_MAX, + &ec->A, &ec->B, &ec->base, &ec->order, &ec->params); // сохранить коэффициенты - ec->A = (word*)ec->descr; - ec->B = ec->A + f->n; if (!qrFrom(ec->A, A, ec->f, stack) || !qrFrom(ec->B, B, ec->f, stack)) return FALSE; - // подготовить буферы для описания группы точек - ec->base = ec->B + f->n; - ec->order = ec->base + 2 * f->n; // настроить интерфейсы ec->froma = ec2FromALD; ec->toa = ec2ToALD; @@ -571,7 +647,8 @@ bool_t ec2CreateLD(ec_o* ec, const qr_o* f, const octet A[], const octet B[], ec2DblLD_deep(f->n, f->deep), ec2DblALD_deep(f->n, f->deep)); // настроить заголовок - ec->hdr.keep = sizeof(ec_o) + O_OF_W(5 * f->n + 1); + ec->hdr.keep = sizeof(ec_o) + + memSliceSize(ec2CreateLD_state(f->n), SIZE_MAX); ec->hdr.p_count = 6; ec->hdr.o_count = 1; // все нормально @@ -580,7 +657,8 @@ bool_t ec2CreateLD(ec_o* ec, const qr_o* f, const octet A[], const octet B[], size_t ec2CreateLD_keep(size_t n) { - return sizeof(ec_o) + O_OF_W(5 * n + 1); + return sizeof(ec_o) + + memSliceSize(ec2CreateLD_state(n), SIZE_MAX); } size_t ec2CreateLD_deep(size_t n, size_t f_deep) @@ -620,18 +698,25 @@ size_t ec2IsValid_deep(size_t n) return gf2IsValid_deep(n); } -bool_t ec2SeemsValidGroup(const ec_o* ec, void* stack) +#define ec2GroupSeemsValid_local(n)\ +/* t1 */ O_OF_W(n + 1),\ +/* t2 */ O_OF_W(n + 2),\ +/* t3 */ O_OF_W(2 * n) + +bool_t ec2GroupSeemsValid(const ec_o* ec, void* stack) { size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n + 1; - word* t3 = t2 + n + 2; - stack = t3 + 2 * n; + word* t1; /* [n + 1] */ + word* t2; /* [n + 2] */ + word* t3; /* [2 * n] */ // pre ASSERT(ecIsOperable(ec)); - // ecIsOperableGroup(ec) == TRUE? base \in ec? - if (!ecIsOperableGroup(ec) || + // разметить стек + memSlice(stack, + ec2GroupSeemsValid_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); + // ecGroupIsOperable(ec)? base \in ec? + if (!ecGroupIsOperable(ec) || !ec2IsOnA(ec->base, ec, stack)) return FALSE; // [n + 1]t1 <- 2^m @@ -660,24 +745,32 @@ bool_t ec2SeemsValidGroup(const ec_o* ec, void* stack) return wwCmp2(t3, 2 * n, t3, ec->f->n + 1) <= 0; } -size_t ec2SeemsValidGroup_deep(size_t n, size_t f_deep) +size_t ec2GroupSeemsValid_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n + 3) + + return memSliceSize( + ec2GroupSeemsValid_local(n), utilMax(2, ec2IsOnA_deep(n, f_deep), - zzSqr_deep(n)); + zzSqr_deep(n)), + SIZE_MAX); } -bool_t ec2IsSafeGroup(const ec_o* ec, size_t mov_threshold, void* stack) +#define ec2GroupIsSafe_local(n1)\ +/* t1 */ O_OF_W(n1),\ +/* t2 */ O_OF_W(n1) + +bool_t ec2GroupIsSafe(const ec_o* ec, size_t mov_threshold, void* stack) { size_t n1 = ec->f->n + 1; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n1; - stack = t2 + n1; + word* t1; /* [n1] */ + word* t2; /* [n1] */ // pre ASSERT(ecIsOperable(ec)); - ASSERT(ecIsOperableGroup(ec)); + ASSERT(ecGroupIsOperable(ec)); + // разметить стек + memSlice(stack, + ec2GroupIsSafe_local(n1), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // order -- простое? n1 = wwWordSize(ec->order, n1); if (!priIsPrime(ec->order, n1, stack)) @@ -706,14 +799,16 @@ bool_t ec2IsSafeGroup(const ec_o* ec, size_t mov_threshold, void* stack) return TRUE; } -size_t ec2IsSafeGroup_deep(size_t n) +size_t ec2GroupIsSafe_deep(size_t n) { const size_t n1 = n + 1; - return O_OF_W(2 * n1) + + return memSliceSize( + ec2GroupIsSafe_local(n1), utilMax(3, priIsPrime_deep(n1), zzMod_deep(n + 1, n1), - zzMulMod_deep(n1)); + zzMulMod_deep(n1)), + SIZE_MAX); } /* @@ -728,15 +823,21 @@ size_t ec2IsSafeGroup_deep(size_t n) ******************************************************************************* */ +#define ec2IsOnA_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + bool_t ec2IsOnA(const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec)); + // разметить стек + memSlice(stack, + ec2IsOnA_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // xa, ya \in ec->f? if (!ec2SeemsOnA(a, ec)) return FALSE; @@ -754,7 +855,10 @@ bool_t ec2IsOnA(const word a[], const ec_o* ec, void* stack) size_t ec2IsOnA_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ec2IsOnA_local(n), + f_deep, + SIZE_MAX); } void ec2NegA(word b[], const word a[], const ec_o* ec) @@ -769,20 +873,27 @@ void ec2NegA(word b[], const word a[], const ec_o* ec) gf2Add(ecY(b, n), ecX(a), ecY(a, n), ec->f); } +#define ec2AddAA_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n) + bool_t ec2AddAA(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - stack = t3 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ // pre ASSERT(ecIsOperable(ec)); ASSERT(ec2SeemsOnA(a, ec)); ASSERT(ec2SeemsOnA(b, ec)); ASSERT(wwIsDisjoint(a, c, 2 * n)); + // разметить стек + memSlice(stack, + ec2AddAA_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); // xa == xb => (xa, ya) == \pm(xb, yb) if (qrCmp(ecX(a), ecX(b), ec->f) == 0) { @@ -837,16 +948,24 @@ bool_t ec2AddAA(word c[], const word a[], const word b[], const ec_o* ec, size_t ec2AddAA_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + f_deep; + return memSliceSize( + ec2AddAA_local(n), + f_deep, + SIZE_MAX); } +#define ec2SubAA_local(n)\ +/* t */ O_OF_W(2 * n) + bool_t ec2SubAA(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t = (word*)stack; - stack = t + 2 * n; + word* t; /* [2 * n] */ + // разметить стек + memSlice(stack, + ec2SubAA_local(n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- -b ec2NegA(t, b, ec); // с <- a + t @@ -855,5 +974,8 @@ bool_t ec2SubAA(word c[], const word a[], const word b[], const ec_o* ec, size_t ec2SubAA_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + ec2AddAA_deep(n, f_deep); + return memSliceSize( + ec2SubAA_local(n), + ec2AddAA_deep(n, f_deep), + SIZE_MAX); } diff --git a/src/math/ecp.c b/src/math/ecp.c index ed6f0662..64f71a12 100644 --- a/src/math/ecp.c +++ b/src/math/ecp.c @@ -4,7 +4,7 @@ \brief Elliptic curves over prime fields \project bee2 [cryptographic library] \created 2012.06.26 -\version 2025.06.10 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -146,18 +146,24 @@ static bool_t ecpFromAJ(word b[], const word a[], const ec_o* ec, void* stack) return TRUE; } +#define ecpToAJ_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + // [2n]b <- [3n]a (A <- P) static bool_t ecpToAJ(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(a == b || wwIsDisjoint2(a, 3 * n, b, 2 * n)); + // разметить стек + memSlice(stack, + ecpToAJ_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // a == O => b <- O if (qrIsZero(ecZ(a, n), ec->f)) return FALSE; @@ -177,7 +183,10 @@ static bool_t ecpToAJ(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpToAJ_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ecpToAJ_local(n), + f_deep, + SIZE_MAX); } // [3n]b <- -[3n]a (P <- -P) @@ -196,18 +205,24 @@ static void ecpNegJ(word b[], const word a[], const ec_o* ec, void* stack) qrCopy(ecZ(b, n), ecZ(a, n), ec->f); } +#define ecpDblJ_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + // [3n]b <- 2[3n]a (P <- 2P) static void ecpDblJ(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ecpDblJ_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // za == 0 или ya == 0? => b <- O if (qrIsZero(ecZ(a, n), ec->f) || qrIsZero(ecY(a, n), ec->f)) { @@ -258,21 +273,30 @@ static void ecpDblJ(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpDblJ_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ecpDblJ_local(n), + f_deep, + SIZE_MAX); } +#define ecpDblJA3_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + // [3n]b <- 2[3n]a (P <- 2P, A = -3) static void ecpDblJA3(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ecpDblJA3_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // za == 0 или ya == 0? => b <- O if (qrIsZero(ecZ(a, n), ec->f) || qrIsZero(ecY(a, n), ec->f)) { @@ -321,23 +345,34 @@ static void ecpDblJA3(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpDblJA3_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ecpDblJA3_local(n), + f_deep, + SIZE_MAX); } +#define ecpDblAJ_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n) + // [3n]b <- 2[2n]a (P <- 2A) static void ecpDblAJ(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - stack = t4 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOnA(a, ec)); ASSERT(a == b || wwIsDisjoint2(a, 2 * n, b, 3 * n)); + // разметить стек + memSlice(stack, + ecpDblAJ_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &stack); // ya == 0? => b <- O if (qrIsZero(ecY(a, n), ec->f)) { @@ -390,26 +425,37 @@ static void ecpDblAJ(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpDblAJ_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n) + f_deep; + return memSliceSize( + ecpDblAJ_local(n), + f_deep, + SIZE_MAX); } +#define ecpAddJ_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n) + // [3n]c <- [3n]a + [3n]b (P <- P + P) static void ecpAddJ(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - stack = t4 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(ecpSeemsOn3(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(wwIsSameOrDisjoint(b, c, 3 * n)); + // разметить стек + memSlice(stack, + ecpAddJ_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &stack); // a == O => c <- b if (qrIsZero(ecZ(a, n), ec->f)) { @@ -495,29 +541,39 @@ static void ecpAddJ(word c[], const word a[], const word b[], const ec_o* ec, static size_t ecpAddJ_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n) + + return memSliceSize( + ecpAddJ_local(n), utilMax(2, f_deep, - ecpDblJ_deep(n, f_deep)); + ecpDblJ_deep(n, f_deep)), + SIZE_MAX); } +#define ecpAddAJ_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n) + // [3n]c <- [3n]a + [2n]b (P <- P + A) static void ecpAddAJ(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - stack = t4 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(ecpSeemsOnA(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n)); + // разметить стек + memSlice(stack, + ecpAddAJ_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &stack); // a == O => c <- (xb : yb : 1) if (qrIsZero(ecZ(a, n), ec->f)) { @@ -577,26 +633,33 @@ static void ecpAddAJ(word c[], const word a[], const word b[], const ec_o* ec, static size_t ecpAddAJ_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n) + + return memSliceSize( + ecpAddAJ_local(n), utilMax(2, f_deep, - ecpDblAJ_deep(n, f_deep)); + ecpDblJ_deep(n, f_deep)), + SIZE_MAX); } +#define ecpSubJ_local(n)\ +/* t */ O_OF_W(3 * n) + // [3n]c <- [3n]a - [3n]b (P <- P - P) static void ecpSubJ(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t = (word*)stack; - stack = t + 3 * n; + word* t; /* [3n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(ecpSeemsOn3(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(wwIsSameOrDisjoint(b, c, 3 * n)); + // разметить стек + memSlice(stack, + ecpSubJ_local(n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- -b qrCopy(ecX(t), ecX(b), ec->f); zmNeg(ecY(t, n), ecY(b, n), ec->f); @@ -607,23 +670,31 @@ static void ecpSubJ(word c[], const word a[], const word b[], const ec_o* ec, static size_t ecpSubJ_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + ecpAddJ_deep(n, f_deep); + return memSliceSize( + ecpSubJ_local(n), + ecpAddJ_deep(n, f_deep), + SIZE_MAX); } +#define ecpSubAJ_local(n)\ +/* t */ O_OF_W(2 * n) + // [3n]c <- [3n]a - [2n]b (P <- P - A) static void ecpSubAJ(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t = (word*)stack; - stack = t + 2 * n; + word* t; /* [3n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(ecpSeemsOnA(b, ec)); ASSERT(wwIsSameOrDisjoint(a, c, 3 * n)); ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n)); + // разметить стек + memSlice(stack, + ecpSubAJ_local(n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- -b qrCopy(ecX(t), ecX(b), ec->f); zmNeg(ecY(t, n), ecY(b, n), ec->f); @@ -633,27 +704,42 @@ static void ecpSubAJ(word c[], const word a[], const word b[], const ec_o* ec, static size_t ecpSubAJ_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + ecpAddAJ_deep(n, f_deep); + return memSliceSize( + ecpSubAJ_local(n), + ecpAddAJ_deep(n, f_deep), + SIZE_MAX); } +#define ecpTplJ_local(n)\ +/* t0 */ O_OF_W(n),\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n),\ +/* t5 */ O_OF_W(n),\ +/* t6 */ O_OF_W(n),\ +/* t7 */ O_OF_W(n) + // [3n]b <- 3[3n]a (P <- 3P) static void ecpTplJ(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t0 = (word*)stack; - word* t1 = t0 + n; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - word* t5 = t4 + n; - word* t6 = t5 + n; - word* t7 = t6 + n; - stack = t7 + n; + word* t0; /* [n] */ + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ + word* t5; /* [n] */ + word* t6; /* [n] */ + word* t7; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ecpTplJ_local(n), SIZE_0, SIZE_MAX, + &t0, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &stack); // t0 <- xa^2 [XX] qrSqr(t0, ecX(a), ec->f, stack); // t1 <- ya^2 [YY] @@ -718,26 +804,40 @@ static void ecpTplJ(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpTplJ_deep(size_t n, size_t f_deep) { - return O_OF_W(8 * n) + f_deep; + return memSliceSize( + ecpTplJ_local(n), + f_deep, + SIZE_MAX); } +#define ecpTplJA3_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n),\ +/* t4 */ O_OF_W(n),\ +/* t5 */ O_OF_W(n),\ +/* t6 */ O_OF_W(n),\ +/* t7 */ O_OF_W(n) + // [3n]b <- 3[3n]a (P <- 3P) static void ecpTplJA3(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - word* t4 = t3 + n; - word* t5 = t4 + n; - word* t6 = t5 + n; - word* t7 = t6 + n; - stack = t7 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + word* t4; /* [n] */ + word* t5; /* [n] */ + word* t6; /* [n] */ + word* t7; /* [n] */ // pre ASSERT(ecIsOperable(ec) && ec->d == 3); ASSERT(ecpSeemsOn3(a, ec)); ASSERT(wwIsSameOrDisjoint(a, b, 3 * n)); + // разметить стек + memSlice(stack, + ecpTplJA3_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &t4, &t5, &t6, &t7, &stack); // t1 <- ya^2 [YY] qrSqr(t1, ecY(a, n), ec->f, stack); // t2 <- za^2 [ZZ] @@ -798,14 +898,27 @@ static void ecpTplJA3(word b[], const word a[], const ec_o* ec, void* stack) static size_t ecpTplJA3_deep(size_t n, size_t f_deep) { - return O_OF_W(7 * n) + f_deep; + return memSliceSize( + ecpTplJA3_local(n), + f_deep, + SIZE_MAX); } +#define ecpCreateJ_state(n)\ +/* A */ O_OF_W(n),\ +/* B */ O_OF_W(n),\ +/* base */ O_OF_W(2 * n),\ +/* order */ O_OF_W(n + 1),\ +/* params */ SIZE_0 + +#define ecpCreateJ_local(n)\ +/* t */ O_OF_W(n) + bool_t ecpCreateJ(ec_o* ec, const qr_o* f, const octet A[], const octet B[], void* stack) { register bool_t bA3; - word* t; + word* t; /* [n] */ // pre ASSERT(memIsValid(ec, sizeof(ec_o))); ASSERT(gfpIsOperable(f)); @@ -816,25 +929,26 @@ bool_t ecpCreateJ(ec_o* ec, const qr_o* f, const octet A[], const octet B[], return FALSE; // обнулить memSetZero(ec, sizeof(ec_o)); - // зафикисровать размерности + // зафиксировать размерности ec->d = 3; // запомнить базовое поле ec->f = f; + // разметить состояние и стек + memSlice(ec->descr, + ecpCreateJ_state(f->n), SIZE_MAX, + &ec->A, &ec->B, &ec->base, &ec->order, &ec->params); + memSlice(stack, + ecpCreateJ_local(f->n), SIZE_0, SIZE_MAX, + &t, &stack); // сохранить коэффициенты - ec->A = (word*)ec->descr; - ec->B = ec->A + f->n; if (!qrFrom(ec->A, A, ec->f, stack) || !qrFrom(ec->B, B, ec->f, stack)) return FALSE; // t <- -3 - t = (word*)stack; gfpDouble(t, f->unity, f); zmAdd(t, t, f->unity, f); zmNeg(t, t, f); // bA3 <- A == -3? bA3 = qrCmp(t, ec->A, f) == 0; - // подготовить буферы для описания группы точек - ec->base = ec->B + f->n; - ec->order = ec->base + 2 * f->n; // настроить интерфейсы ec->froma = ecpFromAJ; ec->toa = ecpToAJ; @@ -856,7 +970,8 @@ bool_t ecpCreateJ(ec_o* ec, const qr_o* f, const octet A[], const octet B[], ecpDblAJ_deep(f->n, f->deep), bA3 ? ecpTplJA3_deep(f->n, f->deep) : ecpTplJ_deep(f->n, f->deep)); // настроить - ec->hdr.keep = sizeof(ec_o) + O_OF_W(5 * f->n + 1); + ec->hdr.keep = sizeof(ec_o) + + memSliceSize(ecpCreateJ_state(f->n), SIZE_MAX); ec->hdr.p_count = 6; ec->hdr.o_count = 1; // все нормально @@ -866,23 +981,27 @@ bool_t ecpCreateJ(ec_o* ec, const qr_o* f, const octet A[], const octet B[], size_t ecpCreateJ_keep(size_t n) { - return sizeof(ec_o) + O_OF_W(5 * n + 1); + return sizeof(ec_o) + + memSliceSize(ecpCreateJ_state(n), SIZE_MAX); } size_t ecpCreateJ_deep(size_t n, size_t f_deep) { - return utilMax(11, - O_OF_W(n), - ecpToAJ_deep(n, f_deep), - ecpAddJ_deep(n, f_deep), - ecpAddAJ_deep(n, f_deep), - ecpSubJ_deep(n, f_deep), - ecpSubAJ_deep(n, f_deep), - ecpDblJ_deep(n, f_deep), - ecpDblJA3_deep(n, f_deep), - ecpDblAJ_deep(n, f_deep), - ecpTplJ_deep(n, f_deep), - ecpTplJA3_deep(n, f_deep)); + return memSliceSize( + ecpCreateJ_local(n), + utilMax(11, + O_OF_W(n), + ecpToAJ_deep(n, f_deep), + ecpAddJ_deep(n, f_deep), + ecpAddAJ_deep(n, f_deep), + ecpSubJ_deep(n, f_deep), + ecpSubAJ_deep(n, f_deep), + ecpDblJ_deep(n, f_deep), + ecpDblJA3_deep(n, f_deep), + ecpDblAJ_deep(n, f_deep), + ecpTplJ_deep(n, f_deep), + ecpTplJA3_deep(n, f_deep)), + SIZE_MAX); } /* @@ -891,14 +1010,21 @@ size_t ecpCreateJ_deep(size_t n, size_t f_deep) ******************************************************************************* */ +#define ecpIsValid_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n) + bool_t ecpIsValid(const ec_o* ec, void* stack) { size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - stack = t3 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ + // разметить стек + memSlice(stack, + ecpIsValid_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); // кривая работоспособна? // поле ec->f корректно? // f->mod > 3? @@ -932,26 +1058,35 @@ bool_t ecpIsValid(const ec_o* ec, void* stack) size_t ecpIsValid_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + + return memSliceSize( + ecpIsValid_local(n), utilMax(2, f_deep, - gfpIsValid_deep(n)); + gfpIsValid_deep(n)), + SIZE_MAX); } -bool_t ecpSeemsValidGroup(const ec_o* ec, void* stack) +#define ecpGroupSeemsValid_local(n)\ +/* t1 */ O_OF_W(n + 1),\ +/* t2 */ O_OF_W(n + 2),\ +/* t3 */ O_OF_W(2 * n) + +bool_t ecpGroupSeemsValid(const ec_o* ec, void* stack) { size_t n = ec->f->n; int cmp; word w; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n + 1; - word* t3 = t2 + n + 2; - stack = t3 + 2 * n; + word* t1; /* [n + 1] */ + word* t2; /* [n + 2] */ + word* t3; /* [2 * n] */ // pre ASSERT(ecIsOperable(ec)); - // ecIsOperableGroup(ec) == TRUE? base \in ec? - if (!ecIsOperableGroup(ec) || + // разметить стек + memSlice(stack, + ecpGroupSeemsValid_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); + // ecGroupIsOperable(ec) == TRUE? base \in ec? + if (!ecGroupIsOperable(ec) || !ecpIsOnA(ec->base, ec, stack)) return FALSE; // [n + 2]t1 <- order * cofactor @@ -980,24 +1115,32 @@ bool_t ecpSeemsValidGroup(const ec_o* ec, void* stack) return TRUE; } -size_t ecpSeemsValidGroup_deep(size_t n, size_t f_deep) +size_t ecpGroupSeemsValid_deep(size_t n, size_t f_deep) { - return O_OF_W(4 * n + 3) + - utilMax(2, + return memSliceSize( + ecpGroupSeemsValid_local(n), + utilMax(2, ecpIsOnA_deep(n, f_deep), - zzSqr_deep(n)); + zzSqr_deep(n)), + SIZE_MAX); } -bool_t ecpIsSafeGroup(const ec_o* ec, size_t mov_threshold, void* stack) +#define ecpGroupIsSafe_local(n1)\ +/* t1 */ O_OF_W(n1),\ +/* t2 */ O_OF_W(n1) + +bool_t ecpGroupIsSafe(const ec_o* ec, size_t mov_threshold, void* stack) { size_t n1 = ec->f->n + 1; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n1; - stack = t2 + n1; + word* t1; /* [n1] */ + word* t2; /* [n1] */ // pre ASSERT(ecIsOperable(ec)); - ASSERT(ecIsOperableGroup(ec)); + ASSERT(ecGroupIsOperable(ec)); + // разметить стек + memSlice(stack, + ecpGroupIsSafe_local(n1), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // order -- простое? n1 = wwWordSize(ec->order, n1); if (!priIsPrime(ec->order, n1, stack)) @@ -1023,14 +1166,16 @@ bool_t ecpIsSafeGroup(const ec_o* ec, size_t mov_threshold, void* stack) return TRUE; } -size_t ecpIsSafeGroup_deep(size_t n) +size_t ecpGroupIsSafe_deep(size_t n) { const size_t n1 = n + 1; - return O_OF_W(2 * n1) + - utilMax(3, + return memSliceSize( + ecpGroupIsSafe_local(n1), + utilMax(2, priIsPrime_deep(n1), zzMod_deep(n, n1), - zzMulMod_deep(n1)); + zzMulMod_deep(n1)), + SIZE_MAX); } /* @@ -1045,15 +1190,21 @@ size_t ecpIsSafeGroup_deep(size_t n) ******************************************************************************* */ +#define ecpIsOnA_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n) + bool_t ecpIsOnA(const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - stack = t2 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ // pre ASSERT(ecIsOperable(ec)); + // разметить стек + memSlice(stack, + ecpIsOnA_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &stack); // xa, ya \in ec->f? if (!zmIsIn(ecX(a), ec->f) || !zmIsIn(ecY(a, n), ec->f)) return FALSE; @@ -1070,7 +1221,10 @@ bool_t ecpIsOnA(const word a[], const ec_o* ec, void* stack) size_t ecpIsOnA_deep(size_t n, size_t f_deep) { - return O_OF_W(2 * n) + f_deep; + return memSliceSize( + ecpIsOnA_local(n), + f_deep, + SIZE_MAX); } void ecpNegA(word b[], const word a[], const ec_o* ec) @@ -1085,19 +1239,26 @@ void ecpNegA(word b[], const word a[], const ec_o* ec) zmNeg(ecY(b, n), ecY(a, n), ec->f); } +#define ecpAddAA_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n) + bool_t ecpAddAA(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - stack = t3 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ // pre ASSERT(ecIsOperable(ec)); ASSERT(ecpSeemsOnA(a, ec)); ASSERT(ecpSeemsOnA(b, ec)); + // разметить стек + memSlice(stack, + ecpAddAA_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); // xa != xb? if (qrCmp(ecX(a), ecX(b), ec->f) != 0) { @@ -1139,22 +1300,32 @@ bool_t ecpAddAA(word c[], const word a[], const word b[], const ec_o* ec, size_t ecpAddAA_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + f_deep; + return memSliceSize( + ecpAddAA_local(n), + f_deep, + SIZE_MAX); } +#define ecpSubAA_local(n)\ +/* t1 */ O_OF_W(n),\ +/* t2 */ O_OF_W(n),\ +/* t3 */ O_OF_W(n) + bool_t ecpSubAA(word c[], const word a[], const word b[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; - // переменные в stack - word* t1 = (word*)stack; - word* t2 = t1 + n; - word* t3 = t2 + n; - stack = t3 + n; + word* t1; /* [n] */ + word* t2; /* [n] */ + word* t3; /* [n] */ // pre ASSERT(ecIsOperable(ec)); ASSERT(ecpSeemsOnA(a, ec)); ASSERT(ecpSeemsOnA(b, ec)); + // разметить стек + memSlice(stack, + ecpSubAA_local(n), SIZE_0, SIZE_MAX, + &t1, &t2, &t3, &stack); // xa != xb? if (qrCmp(ecX(a), ecX(b), ec->f) != 0) { @@ -1196,7 +1367,10 @@ bool_t ecpSubAA(word c[], const word a[], const word b[], const ec_o* ec, size_t ecpSubAA_deep(size_t n, size_t f_deep) { - return O_OF_W(3 * n) + f_deep; + return memSliceSize( + ecpSubAA_local(n), + f_deep, + SIZE_MAX); } /* @@ -1207,22 +1381,31 @@ size_t ecpSubAA_deep(size_t n, size_t f_deep) ******************************************************************************* */ +#define ecpSWU_local(n)\ +/* t */ O_OF_W(n),\ +/* x1 */ O_OF_W(n),\ +/* x2 */ O_OF_W(n),\ +/* y */ O_OF_W(n),\ +/* s */ O_OF_W(n) + void ecpSWU(word b[], const word a[], const ec_o* ec, void* stack) { const size_t n = ec->f->n; register size_t mask; - // переменные в stack [x2 после x1, s после y!] - word* t = (word*)stack; - word* x1 = t + n; - word* x2 = x1 + n; - word* y = x2 + n; - word* s = y + n; - stack = s + n; + word* t; /* [n] */ + word* x1; /* [n] */ + word* x2; /* [n] */ + word* y; /* [n] */ + word* s; /* [n] */ // pre ASSERT(ecIsOperable(ec)); ASSERT(zmIsIn(a, ec->f)); ASSERT(wwGetBits(ec->f->mod, 0, 2) == 3); ASSERT(!qrIsZero(ec->A, ec->f) && !qrIsZero(ec->B, ec->f)); + // разметить стек + memSlice(stack, + ecpSWU_local(n), SIZE_0, SIZE_MAX, + &t, &x1, &x2, &y, &s, &stack); // t <- -a^2 qrSqr(t, a, ec->f, stack); zmNeg(t, t, ec->f); @@ -1268,8 +1451,10 @@ void ecpSWU(word b[], const word a[], const ec_o* ec, void* stack) size_t ecpSWU_deep(size_t n, size_t f_deep) { - return O_OF_W(5 * n) + + return memSliceSize( + ecpSWU_local(n), utilMax(2, f_deep, - qrPower_deep(n, n, f_deep)); + qrPower_deep(n, n, f_deep)), + SIZE_MAX); } diff --git a/src/math/gf2.c b/src/math/gf2.c index ee3aa96b..87046e24 100644 --- a/src/math/gf2.c +++ b/src/math/gf2.c @@ -4,7 +4,7 @@ \brief Binary fields \project bee2 [cryptographic library] \created 2012.04.17 -\version 2025.06.10 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -227,14 +227,19 @@ static void gf2Neg2(word b[], const word a[], const qr_o* f) wwCopy(b, a, f->n); } +#define gf2MulTrinomial0_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2MulTrinomial0(word c[], const word a[], const word b[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); ASSERT(gf2IsIn(b, f)); + memSlice(stack, + gf2MulTrinomial0_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppMul(prod, a, f->n, b, f->n, stack); gf2RedTrinomial0(prod, f->n, (const gf2_trinom_st*)f->params); wwCopy(c, prod, f->n); @@ -242,17 +247,25 @@ static void gf2MulTrinomial0(word c[], const word a[], const word b[], static size_t gf2MulTrinomial0_deep(size_t n) { - return ppMul_deep(n, n); + return memSliceSize( + gf2MulTrinomial0_local(n), + ppMul_deep(n, n), + SIZE_MAX); } +#define gf2MulTrinomial1_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2MulTrinomial1(word c[], const word a[], const word b[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); ASSERT(gf2IsIn(b, f)); + memSlice(stack, + gf2MulTrinomial1_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppMul(prod, a, f->n, b, f->n, stack); gf2RedTrinomial1(prod, f->n, (const gf2_trinom_st*)f->params); wwCopy(c, prod, f->n); @@ -260,17 +273,25 @@ static void gf2MulTrinomial1(word c[], const word a[], const word b[], static size_t gf2MulTrinomial1_deep(size_t n) { - return ppMul_deep(n, n); + return memSliceSize( + gf2MulTrinomial1_local(n), + ppMul_deep(n, n), + SIZE_MAX); } +#define gf2MulPentanomial_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2MulPentanomial(word c[], const word a[], const word b[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); ASSERT(gf2IsIn(b, f)); + memSlice(stack, + gf2MulPentanomial_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppMul(prod, a, f->n, b, f->n, stack); gf2RedPentanomial(prod, f->n, (const gf2_pentanom_st*)f->params); wwCopy(c, prod, f->n); @@ -278,16 +299,24 @@ static void gf2MulPentanomial(word c[], const word a[], const word b[], static size_t gf2MulPentanomial_deep(size_t n) { - return ppMul_deep(n, n); + return memSliceSize( + gf2MulPentanomial_local(n), + ppMul_deep(n, n), + SIZE_MAX); } +#define gf2SqrTrinomial0_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2SqrTrinomial0(word b[], const word a[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); + memSlice(stack, + gf2SqrTrinomial0_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppSqr(prod, a, f->n, stack); gf2RedTrinomial0(prod, f->n, (const gf2_trinom_st*)f->params); wwCopy(b, prod, f->n); @@ -295,16 +324,24 @@ static void gf2SqrTrinomial0(word b[], const word a[], const qr_o* f, static size_t gf2SqrTrinomial0_deep(size_t n) { - return ppSqr_deep(n); + return memSliceSize( + gf2SqrTrinomial0_local(n), + ppSqr_deep(n), + SIZE_MAX); } +#define gf2SqrTrinomial1_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2SqrTrinomial1(word b[], const word a[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); + memSlice(stack, + gf2SqrTrinomial1_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppSqr(prod, a, f->n, stack); gf2RedTrinomial1(prod, f->n, (const gf2_trinom_st*)f->params); wwCopy(b, prod, f->n); @@ -312,16 +349,24 @@ static void gf2SqrTrinomial1(word b[], const word a[], const qr_o* f, static size_t gf2SqrTrinomial1_deep(size_t n) { - return ppSqr_deep(n); + return memSliceSize( + gf2SqrTrinomial1_local(n), + ppSqr_deep(n), + SIZE_MAX); } +#define gf2SqrPentanomial_local(n)\ +/* prod */ O_OF_W(2 * n) + static void gf2SqrPentanomial(word b[], const word a[], const qr_o* f, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * f->n; + word* prod; /* [2 * n] */ ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); + memSlice(stack, + gf2SqrPentanomial_local(f->n), SIZE_0, SIZE_MAX, + &prod, &stack); ppSqr(prod, a, f->n, stack); gf2RedPentanomial(prod, f->n, (const gf2_pentanom_st*)f->params); wwCopy(b, prod, f->n); @@ -329,17 +374,25 @@ static void gf2SqrPentanomial(word b[], const word a[], const qr_o* f, static size_t gf2SqrPentanomial_deep(size_t n) { - return ppSqr_deep(n); + return memSliceSize( + gf2SqrPentanomial_local(n), + ppSqr_deep(n), + SIZE_MAX); } +#define gf2Inv_local(n)\ +/* c */ O_OF_W(n + 1) + static void gf2Inv(word b[], const word a[], const qr_o* f, void* stack) { ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); if (gf2Deg(f) % B_PER_W == 0) { - word* c = (word*)stack; - stack = c + f->n + 1; + word* c; /* [n + 1] */ + memSlice(stack, + gf2Inv_local(f->n), SIZE_0, SIZE_MAX, + &c, &stack); ppInvMod(c, a, f->mod, f->n + 1, stack); ASSERT(c[f->n] == 0); wwCopy(b, c, f->n); @@ -350,9 +403,15 @@ static void gf2Inv(word b[], const word a[], const qr_o* f, void* stack) static size_t gf2Inv_deep(size_t n) { - return O_OF_W(n + 1) + ppInvMod_deep(n + 1); + return memSliceSize( + gf2Inv_local(n), + ppInvMod_deep(n + 1), + SIZE_MAX); } +#define gf2Div_local(n)\ +/* c */ O_OF_W(n + 1) + static void gf2Div(word b[], const word divident[], const word a[], const qr_o* f, void* stack) { @@ -361,8 +420,10 @@ static void gf2Div(word b[], const word divident[], const word a[], ASSERT(gf2IsIn(a, f)); if (gf2Deg(f) % B_PER_W == 0) { - word* c = (word*)stack; - stack = c + f->n + 1; + word* c; /* [n + 1] */ + memSlice(stack, + gf2Div_local(f->n), SIZE_0, SIZE_MAX, + &c, &stack); ppDivMod(c, divident, a, f->mod, f->n + 1, stack); ASSERT(c[f->n] == 0); wwCopy(b, c, f->n); @@ -373,7 +434,10 @@ static void gf2Div(word b[], const word divident[], const word a[], static size_t gf2Div_deep(size_t n) { - return O_OF_W(n + 1) + ppDivMod_deep(n + 1); + return memSliceSize( + gf2Div_local(n), + ppInvMod_deep(n + 1), + SIZE_MAX); } /* @@ -382,8 +446,15 @@ static size_t gf2Div_deep(size_t n) ******************************************************************************* */ +#define gf2Create_state(n, n1)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n1),\ +/* params */ MAX2(sizeof(gf2_trinom_st), sizeof(gf2_pentanom_st)) + bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) { + size_t n1; + // pre ASSERT(memIsValid(f, sizeof(qr_o))); ASSERT(memIsValid(p, 4 * sizeof(size_t))); // нормальный базис? @@ -395,29 +466,44 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) // трехчлен? else if (p[2] == 0) { - gf2_trinom_st* t; - size_t n1; // нарушены соглашения? if (p[3] != 0) return FALSE; // нарушены условия функции ppRedTrinomial? if (p[0] % 8 == 0 || p[1] >= p[0] || p[0] - p[1] < B_PER_W) return FALSE; - // зафиксировать размерность - f->n = W_OF_B(p[0]); - n1 = f->n + (p[0] % B_PER_W == 0); - f->no = O_OF_B(p[0]); + } + // пятичлен? + else + { + // нарушены соглашения? + if (p[3] == 0) + return FALSE; + // нарушены условия функции ppRedPentanomial? + if (p[1] >= p[0] || p[2] >= p[1] || p[3] >= p[2] || + p[0] - p[1] < B_PER_W || p[1] >= B_PER_W) + return FALSE; + } + // зафиксировать размерность + f->n = W_OF_B(p[0]); + n1 = f->n + (p[0] % B_PER_W == 0); + f->no = O_OF_B(p[0]); + // разметить состояние + memSlice(f->descr, + gf2Create_state(f->n, n1), SIZE_MAX, + &f->mod, &f->unity, &f->params); + // трехчлен? + if (p[2] == 0) + { + gf2_trinom_st* t; // сформировать mod - f->mod = (word*)f->descr; wwSetZero(f->mod, n1); wwSetBit(f->mod, p[0], 1); wwSetBit(f->mod, p[1], 1); wwSetBit(f->mod, 0, 1); // сформировать unity - f->unity = f->mod + n1; wwSetW(f->unity, f->n, 1); // сформировать params - f->params = (size_t*)(f->unity + f->n); t = (gf2_trinom_st*)f->params; t->m = p[0]; t->k = p[1]; @@ -436,10 +522,6 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) f->sqr = t->bk == 0 ? gf2SqrTrinomial0 : gf2SqrTrinomial1; f->inv = gf2Inv; f->div = gf2Div; - // заголовок - f->hdr.keep = sizeof(qr_o) + O_OF_W(n1 + f->n) + sizeof(gf2_trinom_st); - f->hdr.p_count = 3; - f->hdr.o_count = 0; // глубина стека if (t->bk == 0) f->deep = utilMax(4, @@ -458,20 +540,11 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) else { gf2_pentanom_st* t; - size_t n1; - // нарушены соглашения? - if (p[3] == 0) - return FALSE; - // нарушены условия функции ppRedPentanomial? - if (p[1] >= p[0] || p[2] >= p[1] || p[3] >= p[2] || - p[0] - p[1] < B_PER_W || p[1] >= B_PER_W) - return FALSE; // зафиксировать размерность f->n = W_OF_B(p[0]); n1 = f->n + (p[0] % B_PER_W == 0); f->no = O_OF_B(p[0]); // сформировать mod - f->mod = (word*)f->descr; wwSetZero(f->mod, n1); wwSetBit(f->mod, p[0], 1); wwSetBit(f->mod, p[1], 1); @@ -479,10 +552,8 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) wwSetBit(f->mod, p[3], 1); wwSetBit(f->mod, 0, 1); // сформировать unity - f->unity = f->mod + n1; wwSetW(f->unity, f->n, 1); // сформировать params - f->params = (size_t*)(f->unity + f->n); t = (gf2_pentanom_st*)f->params; t->m = p[0]; t->k = p[1]; @@ -506,11 +577,6 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) f->sqr = gf2SqrPentanomial; f->inv = gf2Inv; f->div = gf2Div; - // заголовок - f->hdr.keep = sizeof(qr_o) + O_OF_W(n1 + f->n) + - sizeof(gf2_pentanom_st); - f->hdr.p_count = 3; - f->hdr.o_count = 0; // глубина стека f->deep = utilMax(4, gf2MulPentanomial_deep(f->n), @@ -518,6 +584,12 @@ bool_t gf2Create(qr_o* f, const size_t p[4], void* stack) gf2Inv_deep(f->n), gf2Div_deep(f->n)); } + // заголовок + f->hdr.keep = sizeof(qr_o) + + memSliceSize(gf2Create_state(f->n, n1), SIZE_MAX); + f->hdr.p_count = 3; + f->hdr.o_count = 0; + // завершение return TRUE; } @@ -525,10 +597,8 @@ size_t gf2Create_keep(size_t m) { const size_t n = W_OF_B(m); const size_t n1 = n + (m % B_PER_W == 0); - return sizeof(qr_o) + O_OF_W(n1 + n) + - utilMax(2, - sizeof(gf2_trinom_st), - sizeof(gf2_pentanom_st)); + return sizeof(qr_o) + + memSliceSize(gf2Create_state(n, n1), SIZE_MAX); } size_t gf2Create_deep(size_t m) @@ -576,7 +646,7 @@ bool_t gf2IsValid(const qr_o* f, void* stack) { // согласованность const size_t n1 = f->n + (p[0] % B_PER_W == 0); - word* mod = (word*)stack; + word* mod = (word*)stack; /* [n1] */ wwSetZero(mod, n1); wwSetBit(mod, p[0], 1); wwSetBit(mod, p[1], 1); @@ -593,7 +663,9 @@ bool_t gf2IsValid(const qr_o* f, void* stack) size_t gf2IsValid_deep(size_t n) { - return O_OF_W(n + 1) + ppIsIrred_deep(n + 1); + return utilMax(2, + O_OF_W(n + 1), + ppIsIrred_deep(n + 1)); } size_t gf2Deg(const qr_o* f) @@ -610,14 +682,20 @@ size_t gf2Deg(const qr_o* f) ******************************************************************************* */ +#define gf2Tr_local(n)\ +/* t */ O_OF_W(n) + bool_t gf2Tr(const word a[], const qr_o* f, void* stack) { size_t m = gf2Deg(f); - word* t = (word*)stack; - stack = t + f->n; + word* t; /* [n] */ // pre ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); + // разметить стек + memSlice(stack, + gf2Tr_local(f->n), SIZE_0, SIZE_MAX, + &t, &stack); // t <- sum_{i = 0}^{m - 1} a^{2^i} qrCopy(t, a, f); while (--m) @@ -635,21 +713,30 @@ bool_t gf2Tr(const word a[], const qr_o* f, void* stack) size_t gf2Tr_deep(size_t n, size_t f_deep) { - return O_OF_W(n) + f_deep; + return memSliceSize( + gf2Tr_local(n), + f_deep, + SIZE_MAX); } +#define gf2QSolve_local(n)\ +/* t */ O_OF_W(n) + bool_t gf2QSolve(word x[], const word a[], const word b[], const qr_o* f, void* stack) { size_t m = gf2Deg(f); - word* t = (word*)stack; - stack = t + f->n; + word* t; /* [n] */ // pre ASSERT(gf2IsOperable(f)); ASSERT(gf2IsIn(a, f)); ASSERT(gf2IsIn(b, f)); ASSERT(x + f->n <= a || x >= a + f->n); ASSERT(m % 2); + // разметить стек + memSlice(stack, + gf2QSolve_local(f->n), SIZE_0, SIZE_MAX, + &t, &stack); // a == 0? if (qrIsZero(a, f)) { @@ -688,5 +775,8 @@ bool_t gf2QSolve(word x[], const word a[], const word b[], size_t gf2QSolve_deep(size_t n, size_t f_deep) { - return O_OF_W(n) + f_deep; + return memSliceSize( + gf2QSolve_local(n), + f_deep, + SIZE_MAX); } diff --git a/src/math/pp/pp_etc.c b/src/math/pp/pp_etc.c index f5a5801b..0cd9d539 100644 --- a/src/math/pp/pp_etc.c +++ b/src/math/pp/pp_etc.c @@ -4,7 +4,7 @@ \brief Binary polynomials: other functions \project bee2 [cryptographic library] \created 2012.03.01 -\version 2025.05.07 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -53,12 +53,19 @@ Irreducible Polynomials over Finite Fields] этот алгоритм обраб ******************************************************************************* */ +#define ppIsIrred_local(n)\ +/* h */ O_OF_W(n),\ +/* d */ O_OF_W(n) + bool_t ppIsIrred(const word a[], size_t n, void* stack) { size_t i; - word* h = (word*)stack; - word* d = h + n; - stack = d + n; + word* h; /* [n] */ + word* d; /* [n] */ + // разметить стек + memSlice(stack, + ppIsIrred_local(n), SIZE_0, SIZE_MAX, + &h, &d, &stack); // нормализация (нужна для \mod a) n = wwWordSize(a, n); // постоянный многочлен не является неприводимым @@ -86,7 +93,12 @@ bool_t ppIsIrred(const word a[], size_t n, void* stack) size_t ppIsIrred_deep(size_t n) { - return O_OF_W(2 * n); + return memSliceSize( + ppIsIrred_local(n), + utilMax(2, + ppGCD_deep(n, n), + ppSqrMod_deep(n)), + SIZE_MAX); } /* @@ -115,21 +127,31 @@ and Algebra]. В последней работе можно найти обос ******************************************************************************* */ +#define ppMinPoly_local(n, m)\ +/* aa */ O_OF_W(2 * n),\ +/* bb */ O_OF_W(2 * n + 1),\ +/* q */ O_OF_W(n + 2),\ +/* r */ O_OF_W(2 * n),\ +/* da */ O_OF_W(m),\ +/* db */ O_OF_W(m + n + 2) + void ppMinPoly(word b[], const word a[], size_t l, void* stack) { const size_t n = W_OF_B(l); const size_t m = W_OF_B(l + 1); size_t na, nb; - // переменные в stack - word* aa = (word*)stack; - word* bb = aa + 2 * n; - word* q = bb + 2 * n + 1; - word* r = q + n + 2; - word* da = r + 2 * n; - word* db = da + m; - stack = db + m + n + 2; + word* aa; /* [2 * n] */ + word* bb; /* [2 * n + 1] */ + word* q; /* [n + 2] */ + word* r; /* [2 * n] */ + word* da; /* [m] */ + word* db; /* [m + n + 2] */ // pre ASSERT(wwIsValid(b, m) && wwIsValid(a, 2 * n)); + // разметить стек + memSlice(stack, + ppMinPoly_local(n, m), SIZE_0, SIZE_MAX, + &aa, &bb, &q, &r, &da, &db, &stack); // aa <- a wwCopy(aa, a, 2 * n); wwTrimHi(aa, 2 * n, 2 * l); @@ -171,20 +193,32 @@ size_t ppMinPoly_deep(size_t l) { const size_t n = W_OF_B(l); const size_t m = W_OF_B(l + 1); - return O_OF_W(8 * n + 2 * m + 5) + ppAddMulW_deep(m); + return memSliceSize( + ppMinPoly_local(n, m), + utilMax(2, + ppDiv_deep(2 * n + 1, 2 * n), + ppAddMulW_deep(m)), + SIZE_MAX); } +#define ppMinPolyMod_local(n)\ +/* t */ O_OF_W(n),\ +/* s */ O_OF_W(2 * n) + void ppMinPolyMod(word b[], const word a[], const word mod[], size_t n, void* stack) { - size_t l, i; - // раскладка стека - word* t = (word*)stack; - word* s = t + n; - stack = s + 2 * n; + size_t l; + size_t i; + word* t; /* [n] */ + word* s; /* [2 * n] */ // pre ASSERT(wwIsValid(b, n) && wwIsValid(a, n) && wwIsValid(mod, n)); ASSERT(wwCmpW(mod, n, 1) > 0 && wwCmp(a, mod, n) < 0); + // разметить стек + memSlice(stack, + ppMinPolyMod_local(n), SIZE_0, SIZE_MAX, + &t, &s, &stack); // l <- \deg(mod) l = ppDeg(mod, n); // s[2 * l - 1 - i] <- a(x)^i при x = 0 @@ -202,5 +236,10 @@ void ppMinPolyMod(word b[], const word a[], const word mod[], size_t n, size_t ppMinPolyMod_deep(size_t n) { - return ppMulMod_deep(n) + ppMinPoly_deep(n * B_PER_W); + return memSliceSize( + ppMinPolyMod_local(n), + utilMax(2, + ppMulMod_deep(n), + ppMinPoly_deep(n * B_PER_W)), + SIZE_MAX); } diff --git a/src/math/pp/pp_gcd.c b/src/math/pp/pp_gcd.c index a5e038f0..8f7bdb40 100644 --- a/src/math/pp/pp_gcd.c +++ b/src/math/pp/pp_gcd.c @@ -4,7 +4,7 @@ \brief Binary polynomials: Euclidian gcd algorithms \project bee2 [cryptographic library] \created 2012.03.01 -\version 2025.06.10 +\version 2025.09.14 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -58,17 +58,24 @@ ******************************************************************************* */ +#define ppGCD_local(n, m)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(m) + void ppGCD(word d[], const word a[], size_t n, const word b[], size_t m, void* stack) { register size_t s; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; + word* u; /* [n] */ + word* v; /* [m] */ // pre ASSERT(wwIsDisjoint2(a, n, d, MIN2(n, m))); ASSERT(wwIsDisjoint2(b, m, d, MIN2(n, m))); ASSERT(!wwIsZero(a, n) && !wwIsZero(b, m)); + // разметить стек + memSlice(stack, + ppGCD_local(n, m), SIZE_MAX, + &u, &v); // d <- 0 wwSetZero(d, MIN2(n, m)); // u <- a, v <- b @@ -107,21 +114,31 @@ void ppGCD(word d[], const word a[], size_t n, const word b[], size_t m, size_t ppGCD_deep(size_t n, size_t m) { - return O_OF_W(n + m); + return memSliceSize( + ppGCD_local(n, m), + SIZE_MAX); } +#define ppExGCD_local(n, m)\ +/* aa */ O_OF_W(n),\ +/* bb */ O_OF_W(m),\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(m),\ +/* da0 */ O_OF_W(m),\ +/* db0 */ O_OF_W(n) + void ppExGCD(word d[], word da[], word db[], const word a[], size_t n, const word b[], size_t m, void* stack) { register size_t s; - size_t nu, mv; - // переменные в stack - word* aa = (word*)stack; - word* bb = aa + n; - word* u = bb + m; - word* v = u + n; - word* da0 = v + m; - word* db0 = da0 + m; + size_t nu; + size_t mv; + word* aa; /* [n] */ + word* bb; /* [m] */ + word* u; /* [n] */ + word* v; /* [m] */ + word* da0; /* [m] */ + word* db0; /* [n] */ // pre ASSERT(wwIsDisjoint3(da, m, db, n, d, MIN2(n, m))); ASSERT(wwIsDisjoint2(a, n, da, m)); @@ -129,6 +146,10 @@ void ppExGCD(word d[], word da[], word db[], const word a[], size_t n, ASSERT(wwIsDisjoint2(a, n, db, n)); ASSERT(wwIsDisjoint2(b, m, db, n)); ASSERT(!wwIsZero(a, n) && !wwIsZero(b, m)); + // разметить стек + memSlice(stack, + ppExGCD_local(n, m), SIZE_MAX, + &aa, &bb, &u, &v, &da0, &db0); // d <- 0, da0 <- 1, db0 <- 0, da <- 0, db <- 1 wwSetZero(d, MIN2(n, m)); wwSetW(da0, m, 1); @@ -209,6 +230,8 @@ void ppExGCD(word d[], word da[], word db[], const word a[], size_t n, size_t ppExGCD_deep(size_t n, size_t m) { - return O_OF_W(3 * n + 3 * m); + return memSliceSize( + ppExGCD_local(n, m), + SIZE_MAX); } diff --git a/src/math/pp/pp_mod.c b/src/math/pp/pp_mod.c index 1c1582c2..123d5155 100644 --- a/src/math/pp/pp_mod.c +++ b/src/math/pp/pp_mod.c @@ -4,7 +4,7 @@ \brief Binary polynomials: modular arithmetic \project bee2 [cryptographic library] \created 2012.03.01 -\version 2025.05.12 +\version 2025.09.13 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -30,15 +30,21 @@ ******************************************************************************* */ +#define ppMulMod_local(n)\ +/* prod */ O_OF_W(2 * n) + void ppMulMod(word c[], const word a[], const word b[], const word mod[], size_t n, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * n; + word* prod; /* [2 * n] */ // pre ASSERT(wwCmp(a, mod, n) < 0 && wwCmp(b, mod, n) < 0); ASSERT(n > 0 && mod[n - 1] != 0); ASSERT(wwIsValid(c, n)); + // разметить стек + memSlice(stack, + ppMulMod_local(n), SIZE_0, SIZE_MAX, + &prod, &stack); // умножить ppMul(prod, a, n, b, n, stack); // привести по модулю @@ -47,21 +53,29 @@ void ppMulMod(word c[], const word a[], const word b[], const word mod[], size_t ppMulMod_deep(size_t n) { - return O_OF_W(2 * n) + + return memSliceSize( + ppMulMod_local(n), utilMax(2, ppMul_deep(n, n), - ppMod_deep(2 * n, n)); + ppMod_deep(2 * n, n)), + SIZE_MAX); } +#define ppSqrMod_local(n)\ +/* sqr */ O_OF_W(2 * n) + void ppSqrMod(word b[], const word a[], const word mod[], size_t n, void* stack) { - word* sqr = (word*)stack; - stack = sqr + 2 * n; + word* sqr; // pre ASSERT(wwCmp(a, mod, n) < 0); ASSERT(n > 0 && mod[n - 1] != 0); ASSERT(wwIsValid(b, n)); + // разметить стек + memSlice(stack, + ppSqrMod_local(n), SIZE_0, SIZE_MAX, + &sqr, &stack); // вычисления ppSqr(sqr, a, n, stack); ppMod(b, sqr, 2 * n, mod, n, stack); @@ -69,26 +83,38 @@ void ppSqrMod(word b[], const word a[], const word mod[], size_t n, size_t ppSqrMod_deep(size_t n) { - return O_OF_W(2 * n) + + return memSliceSize( + ppSqrMod_local(n), utilMax(2, ppSqr_deep(n), - ppMod_deep(2 * n, n)); + ppMod_deep(2 * n, n)), + SIZE_MAX); } +#define ppDivMod_local(n)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(n),\ +/* da0 */ O_OF_W(n),\ +/* da */ O_OF_W(n) + void ppDivMod(word b[], const word divident[], const word a[], const word mod[], size_t n, void* stack) { - size_t nu, nv; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; - word* da0 = v + n; - word* da = da0 + n; + size_t nu; + size_t nv; + word* u; /* [n] */ + word* v; /* [n] */ + word* da0; /* [n] */ + word* da; /* [n] */ // pre ASSERT(wwCmp(a, mod, n) < 0); ASSERT(wwCmp(divident, mod, n) < 0); ASSERT(n > 0 && mod[n - 1] != 0 && wwTestBit(mod, 0)); ASSERT(wwIsValid(b, n)); + // разметить стек + memSlice(stack, + ppDivMod_local(n), SIZE_MAX, + &u, &v, &da0, &da); // da0 <- divident, da <- 0 wwCopy(da0, divident, n); wwSetZero(da, n); @@ -146,20 +172,29 @@ void ppDivMod(word b[], const word divident[], const word a[], size_t ppDivMod_deep(size_t n) { - return O_OF_W(4 * n); + return memSliceSize( + ppDivMod_local(n), + SIZE_MAX); } +#define ppInvMod_local(n)\ +/* u */ O_OF_W(n) + void ppInvMod(word b[], const word a[], const word mod[], size_t n, void* stack) { - word* divident = (word*)stack; - stack = divident + n; + word* divident; /* [n] */ + memSlice(stack, + ppInvMod_local(n), SIZE_0, SIZE_MAX, + ÷nt, &stack); wwSetW(divident, n, 1); ppDivMod(b, divident, a, mod, n, stack); } size_t ppInvMod_deep(size_t n) { - return O_OF_W(n) + ppDivMod_deep(n); + return memSliceSize( + ppInvMod_local(n), + ppDivMod_deep(n), + SIZE_MAX); } - diff --git a/src/math/pp/pp_mul.c b/src/math/pp/pp_mul.c index 1998b673..bf909fa2 100644 --- a/src/math/pp/pp_mul.c +++ b/src/math/pp/pp_mul.c @@ -4,7 +4,7 @@ \brief Binary polynomials: multiplicative operations \project bee2 [cryptographic library] \created 2012.03.01 -\version 2025.06.10 +\version 2025.09.14 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -1221,23 +1221,32 @@ size_t ppSqr_deep(size_t n) ******************************************************************************* */ +#define ppDiv_local(n, m)\ +/* divident */ O_OF_W(n + 1),\ +/* divisor */ O_OF_W(m),\ +/* w1 */ O_OF_W(16),\ +/* w1 */ O_OF_W(16) + void ppDiv(word q[], word r[], const word a[], size_t n, const word b[], size_t m, void* stack) { register word dividentHi; register size_t shift; size_t i; - // переменные в stack - word* divident; /* нормализованное делимое (n + 1 слово) */ - word* divisor; /* нормализованный делитель (m слов) */ - word* w1; /* таблица частных (16 слов) */ - word* w2; /* таблица умножения (16 слов) */ + word* divident; /* [n + 1] нормализованное делимое */ + word* divisor; /* [m] нормализованный делитель */ + word* w1; /* [16] таблица частных */ + word* w2; /* [16] таблица умножения */ // pre ASSERT(n >= m); ASSERT(wwIsValid(a, n) && wwIsValid(b, m)); ASSERT(m > 0 && b[m - 1] > 0); ASSERT(wwIsDisjoint2(q, n + 1 - m, r, m)); ASSERT(a == r || wwIsDisjoint2(a, n, r, m)); + // разметить стек + memSlice(stack, + ppDiv_local(n, m), SIZE_0, SIZE_MAX, + ÷nt, &divisor, &w1, &w2, &stack); // deg(a) < deg(b)? if (wwBitSize(a, n) < wwBitSize(b, m)) { @@ -1246,12 +1255,6 @@ void ppDiv(word q[], word r[], const word a[], size_t n, const word b[], wwCopy(r, a, m); return; } - // резервируем переменные в stack - divident = (word*)stack; - divisor = divident + n + 1; - w1 = divisor + m; - w2 = w1 + 16; - stack = w2 + 16; // divident <- a wwCopy(divident, a, n); divident[n] = 0; @@ -1294,9 +1297,18 @@ void ppDiv(word q[], word r[], const word a[], size_t n, const word b[], size_t ppDiv_deep(size_t n, size_t m) { - return O_OF_W(n + 1 + m + 16 + 16) + ppAddMulW_deep(m); + return memSliceSize( + ppDiv_local(n, m), + ppAddMulW_deep(m), + SIZE_MAX); } +#define ppMod_local(n, m)\ +/* divident */ O_OF_W(n + 1),\ +/* divisor */ O_OF_W(m),\ +/* w1 */ O_OF_W(16),\ +/* w1 */ O_OF_W(16) + void ppMod(word r[], const word a[], size_t n, const word b[], size_t m, void* stack) { @@ -1304,15 +1316,18 @@ void ppMod(word r[], const word a[], size_t n, const word b[], size_t m, register word tmp; register size_t shift; size_t i; - // переменные в stack - word* divident; /* нормализованное делимое (n + 1 слово) */ - word* divisor; /* нормализованный делитель (m слов) */ - word* w1; /* таблица частных (16 слов) */ - word* w2; /* таблица умножения (16 слов) */ + word* divident; /* [n + 1] нормализованное делимое */ + word* divisor; /* [m] нормализованный делитель */ + word* w1; /* [16] таблица частных */ + word* w2; /* [16] таблица умножения */ // pre ASSERT(wwIsValid(a, n) && wwIsValid(b, m)); ASSERT(m > 0 && b[m - 1] > 0); ASSERT(a == r || wwIsDisjoint2(a, n, r, m)); + // разметить стек + memSlice(stack, + ppMod_local(n, m), SIZE_0, SIZE_MAX, + ÷nt, &divisor, &w1, &w2, &stack); // deg(a) < deg(b)? if (wwBitSize(a, n) < wwBitSize(b, m)) { @@ -1322,12 +1337,6 @@ void ppMod(word r[], const word a[], size_t n, const word b[], size_t m, wwCopy(r, a, m); return; } - // резервируем переменные в stack - divident = (word*)stack; - divisor = divident + n + 1; - w1 = divisor + m; - w2 = w1 + 16; - stack = w2 + 16; // divident <- a wwCopy(divident, a, n); divident[n] = 0; @@ -1370,7 +1379,10 @@ void ppMod(word r[], const word a[], size_t n, const word b[], size_t m, size_t ppMod_deep(size_t n, size_t m) { - return O_OF_W(n + 1 + m + 16 + 16) + ppAddMulW_deep(m); + return memSliceSize( + ppMod_local(n, m), + ppAddMulW_deep(m), + SIZE_MAX); } /* снять подавление предупреждения C4146 */ diff --git a/src/math/pp/pp_red.c b/src/math/pp/pp_red.c index f3b36b92..4d895972 100644 --- a/src/math/pp/pp_red.c +++ b/src/math/pp/pp_red.c @@ -139,4 +139,3 @@ void ppRedBelt(word a[]) a[n] >> (B_PER_W - 2) ^ a[n] >> (B_PER_W - 7); } } - diff --git a/src/math/pri.c b/src/math/pri.c index 209a09fe..fdfceb65 100644 --- a/src/math/pri.c +++ b/src/math/pri.c @@ -4,7 +4,7 @@ \brief Prime numbers \project bee2 [cryptographic library] \created 2012.08.13 -\version 2025.06.10 +\version 2025.09.14 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -410,23 +410,27 @@ void priBaseMod(word mods[], const word a[], size_t n, size_t count) ******************************************************************************* */ +#define priIsSieved_local(base_count)\ +/* mods */ O_OF_W(base_count) + bool_t priIsSieved(const word a[], size_t n, size_t base_count, void* stack) { - // переменные в stack - word* mods; + word* mods; /* [base_count] */ // pre ASSERT(base_count <= priBaseSize()); // четное? n = wwWordSize(a, n); if (zzIsEven(a, n)) return FALSE; + // разметить стек + memSlice(stack, + priIsSieved_local(base_count), SIZE_MAX, + &mods); // малое a? if (n == 1) // при необходимости скорректировать факторную базу while (base_count > 0 && priBasePrime(base_count - 1) > a[0]) --base_count; - // раскладка stack - mods = (word*)stack; // найти остатки priBaseMod(mods, a, n, base_count); // есть нулевые остатки? @@ -439,17 +443,25 @@ bool_t priIsSieved(const word a[], size_t n, size_t base_count, void* stack) size_t priIsSieved_deep(size_t base_count) { - return O_OF_W(base_count); + return memSliceSize( + priIsSieved_local(base_count), + SIZE_MAX); } +#define priIsSmooth_local(n)\ +/* t */ O_OF_W(n) + bool_t priIsSmooth(const word a[], size_t n, size_t base_count, void* stack) { register size_t i; register word mod; - // переменные в stack - word* t = (word*)stack; + word* t; /* [n] */ // pre ASSERT(base_count <= priBaseSize()); + // разметить стек + memSlice(stack, + priIsSmooth_local(n), SIZE_MAX, + &t); // t <- a wwCopy(t, a, n); // разделить t на степень 2 @@ -464,7 +476,7 @@ bool_t priIsSmooth(const word a[], size_t n, size_t base_count, void* stack) // цикл по простым из факторной базы for (i = 0; i < base_count;) { - mod = _base[i] < WORD_BIT_HALF ? + mod = _base[i] < WORD_MID ? zzModW2(t, n, _base[i]) : zzModW(t, n, _base[i]); // делится на простое? if (mod == 0) @@ -487,7 +499,9 @@ bool_t priIsSmooth(const word a[], size_t n, size_t base_count, void* stack) size_t priIsSmooth_deep(size_t n) { - return O_OF_W(n); + return memSliceSize( + priIsSmooth_local(n), + SIZE_MAX); } /* @@ -598,19 +612,27 @@ B_PER_IMPOSSLIBLE / log_2(24) <= B_PER_IMPOSSLIBLE / 4.5. ******************************************************************************* */ +#define priRMTest_local(n)\ +/* r */ O_OF_W(n),\ +/* base */ O_OF_W(n),\ +/* qr */ zmCreate_keep(O_OF_W(n)),\ +/* combo_state */ prngCOMBO_keep() + bool_t priRMTest(const word a[], size_t n, size_t iter, void* stack) { register size_t s; register size_t m; register size_t i; - // переменные в stack - word* r = (word*)stack; - word* base = r + n; - qr_o* qr = (qr_o*)(base + n); - octet* combo_state = (octet*)qr + zmCreate_keep(O_OF_W(n)); - stack = combo_state + prngCOMBO_keep(); + word* r; /* [n] */ + word* base; /* [n] */ + qr_o* qr; /* [zmCreate_keep(O_OF_W(n))] */ + octet* combo_state; /* prngCOMBO_keep() */ // pre ASSERT(wwIsValid(a, n)); + // разметить стек + memSlice(stack, + priRMTest_local(n), SIZE_0, SIZE_MAX, + &r, &base, &qr, &combo_state, &stack); // нормализация n = wwWordSize(a, n); // четное? @@ -674,10 +696,12 @@ bool_t priRMTest(const word a[], size_t n, size_t iter, void* stack) size_t priRMTest_deep(size_t n) { size_t qr_deep = zmCreate_deep(O_OF_W(n)); - return O_OF_W(2 * n) + zmCreate_keep(O_OF_W(n)) + prngCOMBO_keep() + + return memSliceSize( + priRMTest_local(n), utilMax(2, qr_deep, - qrPower_deep(n, n, qr_deep)); + qrPower_deep(n, n, qr_deep)), + SIZE_MAX); } bool_t priIsPrime(const word a[], size_t n, void* stack) @@ -700,18 +724,21 @@ q -- нечетное простое => p = 2q + 1 -- простое <=> [тео ******************************************************************************* */ +#define priIsSGPrime_local(n, no)\ +/* p */ O_OF_W(n + 1),\ +/* qr */ zmCreate_keep(no) + bool_t priIsSGPrime(const word q[], size_t n, void* stack) { size_t no = O_OF_W(n + 1); - // переменные в stack - word* p; - qr_o* qr; + word* p; /* [n + 1] */ + qr_o* qr; /* [zmCreate_keep(no)] */ // pre ASSERT(zzIsOdd(q, n) && wwCmpW(q, n, 1) > 0); - // раскладка стек - p = (word*)stack; - qr = (qr_o*)(p + n + 1); - stack = (octet*)qr + zmCreate_keep(no); + // разметить стек + memSlice(stack, + priIsSGPrime_local(n, no), SIZE_0, SIZE_MAX, + &p, &qr, &stack); // p <- 2q + 1 wwCopy(p, q, n); p[n] = 0; @@ -733,10 +760,12 @@ size_t priIsSGPrime_deep(size_t n) { const size_t no = O_OF_W(n + 1); const size_t qr_deep = zmCreate_deep(no); - return no + zmCreate_keep(no) + + return memSliceSize( + priIsSGPrime_local(n, no), utilMax(2, qr_deep, - qrPower_deep(n + 1, n, qr_deep)); + qrPower_deep(n + 1, n, qr_deep)), + SIZE_MAX); } /* @@ -774,20 +803,23 @@ size_t priNextPrimeW_deep() return priIsPrimeW_deep(); } +#define priNextPrime_local(base_count)\ +/* mods */ O_OF_W(base_count) + bool_t priNextPrime(word p[], const word a[], size_t n, size_t trials, size_t base_count, size_t iter, void* stack) { size_t l; size_t i; bool_t base_success; - // переменные в stack - word* mods; + word* mods; /* [base_count] */ // pre ASSERT(wwIsSameOrDisjoint(a, p, n)); ASSERT(base_count <= priBaseSize()); - // раскладка stack - mods = (word*)stack; - stack = mods + base_count; + // разметить стек + memSlice(stack, + priNextPrime_local(base_count), SIZE_0, SIZE_MAX, + &mods, &stack); // l <- битовая длина a l = wwBitSize(a, n); // 0-битовых и 1-битовых простых не существует @@ -833,7 +865,10 @@ bool_t priNextPrime(word p[], const word a[], size_t n, size_t trials, size_t priNextPrime_deep(size_t n, size_t base_count) { - return base_count * O_PER_W + priRMTest_deep(n); + return memSliceSize( + priNextPrime_local(base_count), + priRMTest_deep(n), + SIZE_MAX); } /* @@ -879,6 +914,15 @@ size_t priNextPrime_deep(size_t n, size_t base_count) ******************************************************************************* */ +#define priExtendPrime2_local(n, m, np, npo, base_count)\ +/* qa */ O_OF_W(n + m),\ +/* t */ O_OF_W(np + 2),\ +/* r */ O_OF_W(np - n - m + 3),\ +/* four */ O_OF_W(np),\ +/* mods */ O_OF_W(base_count),\ +/* mods1 */ O_OF_W(base_count),\ +/* qr */ zmCreate_keep(npo) + bool_t priExtendPrime2(word p[], size_t l, const word q[], size_t n, const word a[], size_t m, size_t trials, size_t base_count, gen_i rng, void* rng_state, void* stack) @@ -887,14 +931,13 @@ bool_t priExtendPrime2(word p[], size_t l, const word q[], size_t n, const size_t npo = O_OF_B(l); size_t i; size_t nqa; - // переменные в stack - word* qa; /* [n + m] */ - word* t; /* [np + 2] */ - word* r; /* [np - n - m + 3] */ - word* four; /* [np] */ - word* mods; /* base_count */ - word* mods1; /* base_count */ - qr_o* qr; + word* qa; /* [n + m] */ + word* t; /* [np + 2] */ + word* r; /* [np - n - m + 3] */ + word* four; /* [np] */ + word* mods; /* [base_count] */ + word* mods1; /* [base_count] */ + qr_o* qr; /* [zmCreate_keep(npo)] */ // pre ASSERT(wwIsDisjoint2(p, np, q, n)); ASSERT(wwIsValid(a, m)); @@ -904,15 +947,10 @@ bool_t priExtendPrime2(word p[], size_t l, const word q[], size_t n, ASSERT(l <= 2 * wwBitSize(q, n)); ASSERT(base_count <= priBaseSize()); ASSERT(rng != 0); - // раскладка stack - qa = (word*)stack; - t = qa + n + m; - r = t + np + 2; - four = r + np - n - m + 3; - mods = four + np; - mods1 = mods + base_count; - qr = (qr_o*)(mods1 + base_count); - stack = (octet*)qr + zmCreate_keep(npo); + // разметить стек + memSlice(stack, + priExtendPrime2_local(n, m, np, npo, base_count), SIZE_0, SIZE_MAX, + &qa, &t, &r, &four, &mods, &mods1, &qr, &stack); // малое p? if (l < B_PER_W) // при необходимости уменьшить факторную базу @@ -1002,31 +1040,41 @@ size_t priExtendPrime2_deep(size_t l, size_t n, size_t m, size_t base_count) const size_t qr_deep = zmCreate_deep(npo); ASSERT(np >= n); ASSERT(np + 3 >= n + m); - return O_OF_W(3 * np + 5 + 2 * base_count) + - zmCreate_keep(npo) + + return memSliceSize( + priExtendPrime2_local(n, m, np, npo, base_count), utilMax(5, zzMul_deep(n, m), zzDiv_deep(np, n + m), zzMul_deep(n + m, np - n - m + 3), qr_deep, - qrPower_deep(np, np, qr_deep)); + qrPower_deep(np, np, qr_deep)), + SIZE_MAX); } +#define priExtendPrime_local()\ +/* a */ O_OF_W(1) + bool_t priExtendPrime(word p[], size_t l, const word q[], size_t n, size_t trials, size_t base_count, gen_i rng, void* rng_state, void* stack) { word* a; // pre ASSERT(memIsValid(stack, O_OF_W(1))); + // разметить стек + memSlice(stack, + priExtendPrime_local(), SIZE_0, SIZE_MAX, + &a, &stack); // a <- 1 - a = (word*)stack; a[0] = 1; // расширить return priExtendPrime2(p, l, q, n, a, 1, trials, base_count, - rng, rng_state, a + 1); + rng, rng_state, stack); } size_t priExtendPrime_deep(size_t l, size_t n, size_t base_count) { - return O_OF_W(1) + priExtendPrime2_deep(l, n, 1, base_count); + return memSliceSize( + priExtendPrime_local(), + priExtendPrime2_deep(l, n, 1, base_count), + SIZE_MAX); } diff --git a/src/math/qr.c b/src/math/qr.c index b3ada2dc..0271e6d1 100644 --- a/src/math/qr.c +++ b/src/math/qr.c @@ -4,12 +4,13 @@ \brief Quotient rings \project bee2 [cryptographic library] \created 2013.09.14 -\version 2025.06.10 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ +#include "bee2/core/mem.h" #include "bee2/core/util.h" #include "bee2/math/qr.h" #include "bee2/math/ww.h" @@ -94,6 +95,10 @@ static size_t qrCalcSlideWidth(size_t m) return 7; } +#define qrPower_local(n, powers_count)\ +/* power */ O_OF_W(n),\ +/* powers */ O_OF_W(n * powers_count) + void qrPower(word c[], const word a[], const word b[], size_t m, const qr_o* r, void* stack) { @@ -102,18 +107,17 @@ void qrPower(word c[], const word a[], const word b[], size_t m, register word slide; register size_t slide_size; size_t pos; - // переменные в stack - word* power; - word* powers; + word* power; /* [n] */ + word* powers; /* [n * powers_count] */ // pre ASSERT(qrIsOperable(r)); ASSERT(wwIsValid(a, r->n)); ASSERT(wwIsValid(b, m)); ASSERT(wwIsValid(c, r->n)); - // раскладка stack - power = (word*)stack; - powers = power + r->n; - stack = powers + r->n * powers_count; + // разметить стек + memSlice(stack, + qrPower_local(r->n, powers_count), SIZE_0, SIZE_MAX, + &power, &powers, &stack); // b == 0? => с <- unity if (wwIsZero(b, m)) { @@ -179,5 +183,8 @@ void qrPower(word c[], const word a[], const word b[], size_t m, size_t qrPower_deep(size_t n, size_t m, size_t r_deep) { const size_t powers_count = SIZE_1 << (qrCalcSlideWidth(m) - 1); - return O_OF_W(n + n * powers_count) + r_deep; + return memSliceSize( + qrPower_local(n, powers_count), + r_deep, + SIZE_MAX); } diff --git a/src/math/ww.c b/src/math/ww.c index 1b84d44b..9ec59450 100644 --- a/src/math/ww.c +++ b/src/math/ww.c @@ -4,7 +4,7 @@ \brief Arbitrary length words \project bee2 [cryptographic library] \created 2012.04.18 -\version 2025.06.10 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -34,7 +34,7 @@ void wwSwap(word a[], word b[], size_t n) SWAP(a[n], b[n]); } -bool_t SAFE(wwEq)(const word a[], const word b[], size_t n) +bool_t wwEq(const word a[], const word b[], size_t n) { register word diff = 0; ASSERT(wwIsValid(a, n) && wwIsValid(b, n)); @@ -52,7 +52,7 @@ bool_t FAST(wwEq)(const word a[], const word b[], size_t n) return TRUE; } -int SAFE(wwCmp)(const word a[], const word b[], size_t n) +int wwCmp(const word a[], const word b[], size_t n) { register word less = 0; register word greater = 0; @@ -76,7 +76,7 @@ int FAST(wwCmp)(const word a[], const word b[], size_t n) return 0; } -int SAFE(wwCmp2)(const word a[], size_t n, const word b[], size_t m) +int wwCmp2(const word a[], size_t n, const word b[], size_t m) { register int ret; ASSERT(wwIsValid(a, n) && wwIsValid(b, m)); @@ -109,7 +109,7 @@ int FAST(wwCmp2)(const word a[], size_t n, const word b[], size_t m) return FAST(wwCmp)(a, b, m); } -int SAFE(wwCmpW)(const word a[], size_t n, register word w) +int wwCmpW(const word a[], size_t n, register word w) { register int ret; ASSERT(wwIsValid(a, n)); @@ -191,7 +191,7 @@ void wwRepW(word a[], size_t n, register word w) CLEAN(w); } -bool_t SAFE(wwIsZero)(const word a[], size_t n) +bool_t wwIsZero(const word a[], size_t n) { register word diff = 0; ASSERT(wwIsValid(a, n)); @@ -209,7 +209,7 @@ bool_t FAST(wwIsZero)(const word a[], size_t n) return TRUE; } -bool_t SAFE(wwIsW)(const word a[], size_t n, register word w) +bool_t wwIsW(const word a[], size_t n, register word w) { register bool_t ret; ASSERT(wwIsValid(a, n)); @@ -241,7 +241,7 @@ bool_t FAST(wwIsW)(const word a[], size_t n, register word w) return ret; } -bool_t SAFE(wwIsRepW)(const word a[], size_t n, register word w) +bool_t wwIsRepW(const word a[], size_t n, register word w) { register bool_t ret; ASSERT(wwIsValid(a, n)); diff --git a/src/math/zm.c b/src/math/zm.c index e829ecef..401382ae 100644 --- a/src/math/zm.c +++ b/src/math/zm.c @@ -4,7 +4,7 @@ \brief Quotient rings of integers modulo m \project bee2 [cryptographic library] \created 2013.09.14 -\version 2016.07.04 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -60,14 +60,19 @@ static void zmNeg2(word b[], const word a[], const qr_o* r) zzNegMod(b, a, r->mod, r->n); } +#define zmMul_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmMul(word c[], const word a[], const word b[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); ASSERT(zmIsIn(b, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmMul_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzMul(prod, a, r->n, b, r->n, stack); zzRed(prod, r->mod, r->n, stack); wwCopy(c, prod, r->n); @@ -75,17 +80,25 @@ static void zmMul(word c[], const word a[], const word b[], static size_t zmMul_deep(size_t n) { - return utilMax(2, - zzMul_deep(n, n), - zzRed_deep(n)); + return memSliceSize( + O_OF_W(2 * n), + utilMax(2, + zzMul_deep(n, n), + zzRed_deep(n)), + SIZE_MAX); } +#define zmSqr_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmSqr(word b[], const word a[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmSqr_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzSqr(prod, a, r->n, stack); zzRed(prod, r->mod, r->n, stack); wwCopy(b, prod, r->n); @@ -93,9 +106,12 @@ static void zmSqr(word b[], const word a[], const qr_o* r, void* stack) static size_t zmSqr_deep(size_t n) { - return utilMax(2, - zzSqr_deep(n), - zzRed_deep(n)); + return memSliceSize( + O_OF_W(2 * n), + utilMax(2, + zzSqr_deep(n), + zzRed_deep(n)), + SIZE_MAX); } static void zmInv(word b[], const word a[], const qr_o* r, void* stack) @@ -124,6 +140,11 @@ static size_t zmDiv_deep(size_t n) return zzDivMod_deep(n); } +#define zmCreatePlain_state(n)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n),\ +/* params */ SIZE_0 + void zmCreatePlain(qr_o* r, const octet mod[], size_t no, void* stack) { ASSERT(memIsValid(r, sizeof(qr_o))); @@ -132,15 +153,15 @@ void zmCreatePlain(qr_o* r, const octet mod[], size_t no, void* stack) // зафиксировать размерности r->n = W_OF_O(no); r->no = no; + // разметить состояние + memSlice(r->descr, + zmCreatePlain_state(r->n), SIZE_MAX, + &r->mod, &r->unity, &r->params); // зафиксировать модуль - r->mod = (word*)r->descr; wwFrom(r->mod, mod, no); // подготовить единицу - r->unity = r->mod + r->n; r->unity[0] = 1; wwSetZero(r->unity + 1, r->n - 1); - // не использовать параметры - r->params = 0; // настроить функции r->from = zmFrom; r->to = zmTo; @@ -157,7 +178,8 @@ void zmCreatePlain(qr_o* r, const octet mod[], size_t no, void* stack) zmInv_deep(r->n), zmDiv_deep(r->n)); // настроить заголовок - r->hdr.keep = sizeof(qr_o) + O_OF_W(2 * r->n); + r->hdr.keep = sizeof(qr_o) + + memSliceSize(zmCreatePlain_state(r->n), SIZE_MAX); r->hdr.p_count = 3; r->hdr.o_count = 0; } @@ -165,7 +187,8 @@ void zmCreatePlain(qr_o* r, const octet mod[], size_t no, void* stack) size_t zmCreatePlain_keep(size_t no) { const size_t n = W_OF_O(no); - return sizeof(qr_o) + O_OF_W(2 * n); + return sizeof(qr_o) + + memSliceSize(zmCreatePlain_state(n), SIZE_MAX); } size_t zmCreatePlain_deep(size_t no) @@ -184,14 +207,19 @@ size_t zmCreatePlain_deep(size_t no) ******************************************************************************* */ +#define zmMulCrand_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmMulCrand(word c[], const word a[], const word b[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); ASSERT(zmIsIn(b, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmMulCrand_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzMul(prod, a, r->n, b, r->n, stack); zzRedCrand(prod, r->mod, r->n, stack); wwCopy(c, prod, r->n); @@ -199,17 +227,25 @@ static void zmMulCrand(word c[], const word a[], const word b[], static size_t zmMulCrand_deep(size_t n) { - return utilMax(2, - zzMul_deep(n, n), - zzRedCrand_deep(n)); + return memSliceSize( + zmMulCrand_local(n), + utilMax(2, + zzMul_deep(n, n), + zzRedCrand_deep(n)), + SIZE_MAX); } +#define zmSqrCrand_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmSqrCrand(word b[], const word a[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmSqrCrand_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzSqr(prod, a, r->n, stack); zzRedCrand(prod, r->mod, r->n, stack); wwCopy(b, prod, r->n); @@ -217,11 +253,19 @@ static void zmSqrCrand(word b[], const word a[], const qr_o* r, void* stack) static size_t zmSqrCrand_deep(size_t n) { - return utilMax(2, - zzSqr_deep(n), - zzRedCrand_deep(n)); + return memSliceSize( + zmSqrCrand_local(n), + utilMax(2, + zzSqr_deep(n), + zzRedCrand_deep(n)), + SIZE_MAX); } +#define zmCreateCrand_state(n)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n),\ +/* params */ SIZE_0 + void zmCreateCrand(qr_o* r, const octet mod[], size_t no, void* stack) { ASSERT(memIsValid(r, sizeof(qr_o))); @@ -233,15 +277,15 @@ void zmCreateCrand(qr_o* r, const octet mod[], size_t no, void* stack) // зафиксировать размерности r->n = W_OF_O(no); r->no = no; + // разметить состояние + memSlice(r->descr, + zmCreateCrand_state(r->n), SIZE_MAX, + &r->mod, &r->unity, &r->params); // зафиксировать модуль - r->mod = (word*)r->descr; wwFrom(r->mod, mod, no); // подготовить единицу - r->unity = r->mod + r->n; r->unity[0] = 1; wwSetZero(r->unity + 1, r->n - 1); - // не использовать параметры - r->params = 0; // настроить функции r->from = zmFrom; r->to = zmTo; @@ -258,7 +302,8 @@ void zmCreateCrand(qr_o* r, const octet mod[], size_t no, void* stack) zmInv_deep(r->n), zmDiv_deep(r->n)); // настроить заголовок - r->hdr.keep = sizeof(qr_o) + O_OF_W(2 * r->n); + r->hdr.keep = sizeof(qr_o) + + memSliceSize(zmCreateCrand_state(r->n), SIZE_MAX); r->hdr.p_count = 3; r->hdr.o_count = 0; } @@ -266,7 +311,8 @@ void zmCreateCrand(qr_o* r, const octet mod[], size_t no, void* stack) size_t zmCreateCrand_keep(size_t no) { const size_t n = W_OF_O(no); - return sizeof(qr_o) + O_OF_W(2 * n); + return sizeof(qr_o) + + memSliceSize(zmCreateCrand_state(n), SIZE_MAX); } size_t zmCreateCrand_deep(size_t no) @@ -285,14 +331,19 @@ size_t zmCreateCrand_deep(size_t no) ******************************************************************************* */ +#define zmMulBarr_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmMulBarr(word c[], const word a[], const word b[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); ASSERT(zmIsIn(b, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmMulBarr_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzMul(prod, a, r->n, b, r->n, stack); zzRedBarr(prod, r->mod, r->n, r->params, stack); wwCopy(c, prod, r->n); @@ -300,17 +351,25 @@ static void zmMulBarr(word c[], const word a[], const word b[], static size_t zmMulBarr_deep(size_t n) { - return utilMax(2, - zzMul_deep(n, n), - zzRedBarr_deep(n)); + return memSliceSize( + zmMulBarr_local(n), + utilMax(2, + zzMul_deep(n, n), + zzRedBarr_deep(n)), + SIZE_MAX); } +#define zmSqrBarr_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmSqrBarr(word b[], const word a[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmSqrBarr_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzSqr(prod, a, r->n, stack); zzRedBarr(prod, r->mod, r->n, r->params, stack); wwCopy(b, prod, r->n); @@ -318,11 +377,19 @@ static void zmSqrBarr(word b[], const word a[], const qr_o* r, void* stack) static size_t zmSqrBarr_deep(size_t n) { - return utilMax(2, - zzSqr_deep(n), - zzRedBarr_deep(n)); + return memSliceSize( + zmSqrBarr_local(n), + utilMax(2, + zzSqr_deep(n), + zzRedBarr_deep(n)), + SIZE_MAX); } +#define zmCreateBarr_state(n)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n),\ +/* params */ O_OF_W(n + 2) + void zmCreateBarr(qr_o* r, const octet mod[], size_t no, void* stack) { ASSERT(memIsValid(r, sizeof(qr_o))); @@ -331,15 +398,16 @@ void zmCreateBarr(qr_o* r, const octet mod[], size_t no, void* stack) // зафиксировать размерности r->n = W_OF_O(no); r->no = no; + // разметить состояние + memSlice(r->descr, + zmCreateBarr_state(r->n), SIZE_MAX, + &r->mod, &r->unity, &r->params); // зафиксировать модуль - r->mod = (word*)r->descr; wwFrom(r->mod, mod, no); // подготовить единицу - r->unity = r->mod + r->n; r->unity[0] = 1; wwSetZero(r->unity + 1, r->n - 1); // подготовить параметры - r->params = r->unity + r->n; zzRedBarrStart(r->params, r->mod, r->n, stack); // настроить функции r->from = zmFrom; @@ -357,7 +425,8 @@ void zmCreateBarr(qr_o* r, const octet mod[], size_t no, void* stack) zmInv_deep(r->n), zmDiv_deep(r->n)); // настроить заголовок - r->hdr.keep = sizeof(qr_o) + O_OF_W(3 * r->n + 2); + r->hdr.keep = sizeof(qr_o) + + memSliceSize(zmCreateBarr_state(r->n), SIZE_MAX); r->hdr.p_count = 3; r->hdr.o_count = 0; } @@ -365,7 +434,8 @@ void zmCreateBarr(qr_o* r, const octet mod[], size_t no, void* stack) size_t zmCreateBarr_keep(size_t no) { const size_t n = W_OF_O(no); - return sizeof(qr_o) + O_OF_W(3 * n + 2); + return sizeof(qr_o) + + memSliceSize(zmCreateBarr_state(n), SIZE_MAX); } size_t zmCreateBarr_deep(size_t no) @@ -394,12 +464,17 @@ Revisited. IEEE Transactions on Computers, 49(7):763–766, 2000]. ******************************************************************************* */ +#define zmFromMont_local(n)\ +/* c */ O_OF_W(2 * n) + static bool_t zmFromMont(word b[], const octet a[], const qr_o* r, void* stack) { - word* c = (word*)stack; + word* c; /* [2 * n] */ ASSERT(zmIsOperable(r)); - stack = c + 2 * r->n; + memSlice(stack, + zmFromMont_local(r->n), SIZE_0, SIZE_MAX, + &c, &stack); // a \in r?, c <- a * R wwFrom(c + r->n, a, r->no); if (!zmIsIn(c + r->n, r)) @@ -412,15 +487,23 @@ static bool_t zmFromMont(word b[], const octet a[], const qr_o* r, static size_t zmFromMont_deep(size_t n) { - return O_OF_W(2 * n) + zzMod_deep(2 * n, n); + return memSliceSize( + zmFromMont_local(n), + zzMod_deep(2 * n, n), + SIZE_MAX); } +#define zmToMont_local(n)\ +/* c */ O_OF_W(2 * n) + static void zmToMont(octet b[], const word a[], const qr_o* r, void* stack) { - word* c = (word*)stack; + word* c; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - stack = c + 2 * r->n; + memSlice(stack, + zmFromMont_local(r->n), SIZE_0, SIZE_MAX, + &c, &stack); // c <- a * R^{-1} \mod mod wwCopy(c, a, r->n); wwSetZero(c + r->n, r->n); @@ -431,17 +514,25 @@ static void zmToMont(octet b[], const word a[], const qr_o* r, void* stack) static size_t zmToMont_deep(size_t n) { - return O_OF_W(2 * n) + zzRedMont_deep(n); + return memSliceSize( + zmToMont_local(n), + zzRedMont_deep(n), + SIZE_MAX); } +#define zmMulMont_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmMulMont(word c[], const word a[], const word b[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); ASSERT(zmIsIn(b, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmMulMont_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzMul(prod, a, r->n, b, r->n, stack); zzRedMont(prod, r->mod, r->n, *(word*)r->params, stack); wwCopy(c, prod, r->n); @@ -449,17 +540,25 @@ static void zmMulMont(word c[], const word a[], const word b[], static size_t zmMulMont_deep(size_t n) { - return utilMax(2, - zzMul_deep(n, n), - zzRedMont_deep(n)); + return memSliceSize( + zmMulMont_local(n), + utilMax(2, + zzMul_deep(n, n), + zzRedMont_deep(n)), + SIZE_MAX); } +#define zmSqrMont_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmSqrMont(word b[], const word a[], const qr_o* r, void* stack) { - word* prod = (word*)stack; + word* prod; /* [2 * n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - stack = prod + 2 * r->n; + memSlice(stack, + zmSqrMont_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); zzSqr(prod, a, r->n, stack); zzRedMont(prod, r->mod, r->n, *(word*)r->params, stack); wwCopy(b, prod, r->n); @@ -467,9 +566,12 @@ static void zmSqrMont(word b[], const word a[], const qr_o* r, void* stack) static size_t zmSqrMont_deep(size_t n) { - return utilMax(2, - zzSqr_deep(n), - zzRedMont_deep(n)); + return memSliceSize( + zmMulMont_local(n), + utilMax(2, + zzSqr_deep(n), + zzRedMont_deep(n)), + SIZE_MAX); } static void zmInvMont(word b[], const word a[], const qr_o* r, void* stack) @@ -484,6 +586,7 @@ static void zmInvMont(word b[], const word a[], const qr_o* r, void* stack) // b <- a^{-1} R^2 \mod mod for (; k < 2 * r->n * B_PER_W; ++k) zzDoubleMod(b, b, r->mod, r->n); + CLEAN(k); } static size_t zmInvMont_deep(size_t n) @@ -491,14 +594,19 @@ static size_t zmInvMont_deep(size_t n) return zzAlmostInvMod_deep(n); } +#define zmDivMont_local(n)\ +/* c */ O_OF_W(n) + static void zmDivMont(word b[], const word divident[], const word a[], const qr_o* r, void* stack) { - word* c = (word*)stack; + word* c; /* [n] */ ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(divident, r)); ASSERT(zmIsIn(a, r)); - stack = c + r->n; + memSlice(stack, + zmDivMont_local(r->n), SIZE_0, SIZE_MAX, + &c, &stack); // c <- a^{(-1)} (в кольце Монтгомери) zmInvMont(c, a, r, stack); // b <- divident * c @@ -507,11 +615,19 @@ static void zmDivMont(word b[], const word divident[], const word a[], static size_t zmDivMont_deep(size_t n) { - return utilMax(2, - zmInvMont_deep(n), - zmMulMont_deep(n)); + return memSliceSize( + zmDivMont_local(n), + utilMax(2, + zmInvMont_deep(n), + zmMulMont_deep(n)), + SIZE_MAX); } +#define zmCreateMont_state(n)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n),\ +/* params */ O_OF_W(1) + void zmCreateMont(qr_o* r, const octet mod[], size_t no, void* stack) { ASSERT(memIsValid(r, sizeof(qr_o))); @@ -521,16 +637,17 @@ void zmCreateMont(qr_o* r, const octet mod[], size_t no, void* stack) // зафиксировать размерности r->n = W_OF_O(no); r->no = no; + // разметить состояние + memSlice(r->descr, + zmCreateMont_state(r->n), SIZE_MAX, + &r->mod, &r->unity, &r->params); // зафиксировать модуль - r->mod = (word*)r->descr; wwFrom(r->mod, mod, no); // подготовить единицу - r->unity = r->mod + r->n; wwSetZero(r->unity, r->n); zzSub2(r->unity, r->mod, r->n); zzMod(r->unity, r->unity, r->n, r->mod, r->n, stack); // подготовить параметры - r->params = r->unity + r->n; *((word*)r->params) = wordNegInv(r->mod[0]); // настроить функции r->from = zmFromMont; @@ -550,7 +667,8 @@ void zmCreateMont(qr_o* r, const octet mod[], size_t no, void* stack) zmInvMont_deep(r->n), zmDivMont_deep(r->n)); // настроить заголовок - r->hdr.keep = sizeof(qr_o) + O_OF_W(2 * r->n + 1); + r->hdr.keep = sizeof(qr_o) + + memSliceSize(zmCreateMont_state(r->n), SIZE_MAX); r->hdr.p_count = 3; r->hdr.o_count = 0; } @@ -558,7 +676,8 @@ void zmCreateMont(qr_o* r, const octet mod[], size_t no, void* stack) size_t zmCreateMont_keep(size_t no) { const size_t n = W_OF_O(no); - return sizeof(qr_o) + O_OF_W(2 * n + 1); + return sizeof(qr_o) + + memSliceSize(zmCreateMont_state(n), SIZE_MAX); } size_t zmCreateMont_deep(size_t no) @@ -647,19 +766,25 @@ typedef struct size_t l; /* размерность */ } zm_mont_params_st; +#define zmMulMont2_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmMulMont2(word c[], const word a[], const word b[], const qr_o* r, void* stack) { - register size_t k; const zm_mont_params_st* params; - word* prod = (word*)stack; + word* prod; /* [2 * n] */ + size_t k; // pre ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); ASSERT(zmIsIn(b, r)); - // настроить указатели + // зафиксировать параметры params = (const zm_mont_params_st*)r->params; - stack = prod + 2 * r->n; + // разметить стек + memSlice(stack, + zmMulMont2_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); // c <- a b B^{-n} \mod mod zzMul(prod, a, r->n, b, r->n, stack); zzRedMont(prod, r->mod, r->n, *(word*)r->params, stack); @@ -671,22 +796,31 @@ static void zmMulMont2(word c[], const word a[], const word b[], static size_t zmMulMont2_deep(size_t n) { - return utilMax(2, - zzMul_deep(n, n), - zzRedMont_deep(n)); + return memSliceSize( + zmMulMont2_local(n), + utilMax(2, + zzMul_deep(n, n), + zzRedMont_deep(n)), + SIZE_MAX); } +#define zmSqrMont2_local(n)\ +/* prod */ O_OF_W(2 * n) + static void zmSqrMont2(word b[], const word a[], const qr_o* r, void* stack) { - register size_t k; const zm_mont_params_st* params; - word* prod = (word*)stack; + word* prod; /* [2 * n] */ + size_t k; // pre ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); - // настроить указатели + // зафиксировать параметры params = (const zm_mont_params_st*)r->params; - stack = prod + 2 * r->n; + // разметить стек + memSlice(stack, + zmSqrMont2_local(r->n), SIZE_0, SIZE_MAX, + &prod, &stack); // b <- a^2 B^{-n} \mod mod zzSqr(prod, a, r->n, stack); zzRedMont(prod, r->mod, r->n, *(word*)r->params, stack); @@ -698,17 +832,22 @@ static void zmSqrMont2(word b[], const word a[], const qr_o* r, void* stack) static size_t zmSqrMont2_deep(size_t n) { - return utilMax(2, - zzSqr_deep(n), - zzRedMont_deep(n)); + return memSliceSize( + zmSqrMont2_local(n), + utilMax(2, + zzSqr_deep(n), + zzRedMont_deep(n)), + SIZE_MAX); } static void zmInvMont2(word b[], const word a[], const qr_o* r, void* stack) { - register size_t k; const zm_mont_params_st* params; + register size_t k; + // pre ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(a, r)); + // зафиксировать параметры params = (const zm_mont_params_st*)r->params; // b <- a^{-1} 2^k \mod mod k = zzAlmostInvMod(b, a, r->mod, r->n, stack); @@ -717,6 +856,7 @@ static void zmInvMont2(word b[], const word a[], const qr_o* r, void* stack) // b <- a^{-1} R^2 \mod mod for (; k < 2 * params->l; ++k) zzDoubleMod(b, b, r->mod, r->n); + CLEAN(k); } static size_t zmInvMont2_deep(size_t n) @@ -724,14 +864,21 @@ static size_t zmInvMont2_deep(size_t n) return zzAlmostInvMod_deep(n); } +#define zmDivMont2_local(n)\ +/* c */ O_OF_W(n) + static void zmDivMont2(word b[], const word divident[], const word a[], const qr_o* r, void* stack) { - word* c = (word*)stack; + word* c; /* [n] */ + // pre ASSERT(zmIsOperable(r)); ASSERT(zmIsIn(divident, r)); ASSERT(zmIsIn(a, r)); - stack = c + r->n; + // разметить стек + memSlice(stack, + zmDivMont2_local(r->n), SIZE_0, SIZE_MAX, + &c, &stack); // c <- a^{(-1)} (в кольце Монтгомери) zmInvMont2(c, a, r, stack); // b <- divident * c @@ -740,11 +887,19 @@ static void zmDivMont2(word b[], const word divident[], const word a[], static size_t zmDivMont2_deep(size_t n) { - return utilMax(2, - zmInvMont2_deep(n), - zmMulMont2_deep(n)); + return memSliceSize( + zmDivMont2_local(n), + utilMax(2, + zmInvMont2_deep(n), + zmMulMont2_deep(n)), + SIZE_MAX); } +#define zmMontCreate_state(n)\ +/* mod */ O_OF_W(n),\ +/* unity */ O_OF_W(n),\ +/* params */ sizeof(zm_mont_params_st) + void zmMontCreate(qr_o* r, const octet mod[], size_t no, size_t l, void* stack) { ASSERT(memIsValid(r, sizeof(qr_o))); @@ -754,12 +909,14 @@ void zmMontCreate(qr_o* r, const octet mod[], size_t no, size_t l, void* stack) // зафиксировать размерности r->n = W_OF_O(no); r->no = no; + // разметить состояние + memSlice(r->descr, + zmMontCreate_state(r->n), SIZE_MAX, + &r->mod, &r->unity, &r->params); // зафиксировать модуль - r->mod = (word*)r->descr; wwFrom(r->mod, mod, no); ASSERT(wwBitSize(r->mod, r->n) <= l && B_OF_W(r->n) >= l); // подготовить единицу: unity <- R \mod mod - r->unity = r->mod + r->n; wwSetZero(r->unity, r->n); if (l == B_OF_W(r->n)) zzSub2(r->unity, r->mod, r->n); @@ -767,7 +924,6 @@ void zmMontCreate(qr_o* r, const octet mod[], size_t no, size_t l, void* stack) wwSetBit(r->unity, l, 1); zzMod(r->unity, r->unity, r->n, r->mod, r->n, stack); // подготовить параметры - r->params = r->unity + r->n; ((zm_mont_params_st*)r->params)->m0 = wordNegInv(r->mod[0]); ((zm_mont_params_st*)r->params)->l = l; // настроить функции @@ -786,7 +942,8 @@ void zmMontCreate(qr_o* r, const octet mod[], size_t no, size_t l, void* stack) zmInvMont2_deep(r->n), zmDivMont2_deep(r->n)); // настроить заголовок - r->hdr.keep = sizeof(qr_o) + O_OF_W(2 * r->n) + sizeof(zm_mont_params_st); + r->hdr.keep = sizeof(qr_o) + + memSliceSize(zmMontCreate_state(r->n), SIZE_MAX); r->hdr.p_count = 3; r->hdr.o_count = 0; } @@ -794,7 +951,8 @@ void zmMontCreate(qr_o* r, const octet mod[], size_t no, size_t l, void* stack) size_t zmMontCreate_keep(size_t no) { const size_t n = W_OF_O(no); - return sizeof(qr_o) + O_OF_W(2 * n) + sizeof(zm_mont_params_st); + return sizeof(qr_o) + + memSliceSize(zmMontCreate_state(n), SIZE_MAX); } size_t zmMontCreate_deep(size_t no) diff --git a/src/math/zz/zz_add.c b/src/math/zz/zz_add.c index 38f08241..47baa50d 100644 --- a/src/math/zz/zz_add.c +++ b/src/math/zz/zz_add.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: additive operations \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -130,7 +130,7 @@ word zzAddW2(word a[], size_t n, register word w) return w; } -bool_t SAFE(zzIsSumEq)(const word c[], const word a[], const word b[], +bool_t zzIsSumEq(const word c[], const word a[], const word b[], size_t n) { register word diff = 0; @@ -176,7 +176,7 @@ bool_t FAST(zzIsSumEq)(const word c[], const word a[], const word b[], return carry == 0; } -bool_t SAFE(zzIsSumWEq)(const word b[], const word a[], size_t n, +bool_t zzIsSumWEq(const word b[], const word a[], size_t n, register word w) { register word diff = 0; diff --git a/src/math/zz/zz_etc.c b/src/math/zz/zz_etc.c index 21214cc9..eddd1af0 100644 --- a/src/math/zz/zz_etc.c +++ b/src/math/zz/zz_etc.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: other functions \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.09.13 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -102,17 +102,23 @@ Handbook of Applied Cryptography] в редакции CТБ 34.101.45 (прил ******************************************************************************* */ +#define zzJacobi_local(n, m)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(m) + int zzJacobi(const word a[], size_t n, const word b[], size_t m, void* stack) { register int t = 1; register size_t s; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; - stack = v + m; + word* u; /* [n] */ + word* v; /* [m] */ // pre ASSERT(wwIsValid(a, n)); ASSERT(zzIsOdd(b, m)); + // разметить стек + memSlice(stack, + zzJacobi_local(n, m), SIZE_0, SIZE_MAX, + &u, &v, &stack); // v <- b wwCopy(v, b, m); m = wwWordSize(v, m); @@ -156,10 +162,12 @@ int zzJacobi(const word a[], size_t n, const word b[], size_t m, void* stack) size_t zzJacobi_deep(size_t n, size_t m) { - return O_OF_W(n + m) + - utilMax(2, - zzMod_deep(n, m), - zzMod_deep(m, n)); + return memSliceSize( + zzJacobi_local(n, m), + utilMax(2, + zzMod_deep(n, m), + zzMod_deep(m, n)), + SIZE_MAX); } /* @@ -187,15 +195,22 @@ size_t zzJacobi_deep(size_t n, size_t m) ******************************************************************************* */ +#define zzSqrt_local(n, m)\ +/* t */ O_OF_W(m + 1),\ +/* r */ O_OF_W(m) + bool_t zzSqrt(word b[], const word a[], size_t n, void* stack) { register int cmp; size_t m = (n + 1) / 2; - word* t = (word*)stack; - word* r = t + m + 1; - stack = r + m; + word* t; /* [m + 1] */ + word* r; /* [m] */ // pre ASSERT(wwIsDisjoint2(a, n, b, m)); + // разметить стек + memSlice(stack, + zzSqrt_local(n, m), SIZE_0, SIZE_MAX, + &t, &r, &stack); // нормализовать a и обработать a == 0 if ((n = wwWordSize(a, n)) == 0) { @@ -237,6 +252,8 @@ bool_t zzSqrt(word b[], const word a[], size_t n, void* stack) size_t zzSqrt_deep(size_t n) { const size_t m = (n + 1) / 2; - return m + 1 + m + zzDiv_deep(n, m); + return memSliceSize( + zzSqrt_local(n, m), + zzDiv_deep(n, m), + SIZE_MAX); } - diff --git a/src/math/zz/zz_gcd.c b/src/math/zz/zz_gcd.c index 244f0133..62e9fec1 100644 --- a/src/math/zz/zz_gcd.c +++ b/src/math/zz/zz_gcd.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: Euclidian gcd algorithms \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -77,17 +77,24 @@ ******************************************************************************* */ +#define zzGCD_local(n, m)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(m) + void zzGCD(word d[], const word a[], size_t n, const word b[], size_t m, void* stack) { register size_t s; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; + word* u; /* [n] */ + word* v; /* [m] */ // pre ASSERT(wwIsDisjoint2(a, n, d, MIN2(n, m))); ASSERT(wwIsDisjoint2(b, m, d, MIN2(n, m))); ASSERT(!wwIsZero(a, n) && !wwIsZero(b, m)); + // разметить стек + memSlice(stack, + zzGCD_local(n, m), SIZE_MAX, + &u, &v); // d <- 0 wwSetZero(d, MIN2(n, m)); // u <- a, v <- b @@ -125,13 +132,22 @@ void zzGCD(word d[], const word a[], size_t n, const word b[], size_t m, size_t zzGCD_deep(size_t n, size_t m) { - return O_OF_W(n + m); + return memSliceSize( + zzGCD_local(n, m), + SIZE_MAX); } -bool_t zzIsCoprime(const word a[], size_t n, const word b[], size_t m, void* stack) +#define zzIsCoprime_local(n, m)\ +/* d */ O_OF_W(MIN2(n, m)) + +bool_t zzIsCoprime(const word a[], size_t n, const word b[], size_t m, + void* stack) { - word* d = (word*)stack; - stack = d + MIN2(n, m); + word* d; /* [MIN2(n, m)] */ + // разметить стек + memSlice(stack, + zzIsCoprime_local(n, m), SIZE_0, SIZE_MAX, + &d, &stack); // a == 0 => (a, b) = b if (wwIsZero(a, n)) return wwIsW(b, m, 1); @@ -145,21 +161,31 @@ bool_t zzIsCoprime(const word a[], size_t n, const word b[], size_t m, void* sta size_t zzIsCoprime_deep(size_t n, size_t m) { - return O_OF_W(MIN2(n, m)) + zzGCD_deep(n, m); + return memSliceSize( + zzIsCoprime_local(n, m), + zzGCD_deep(n, m), + SIZE_MAX); } +#define zzLCM_local(n, m)\ +/* prod */ O_OF_W(n + m),\ +/* gcd */ O_OF_W(MIN2(n, m)),\ +/* r */ O_OF_W(MIN2(n, m)) + void zzLCM(word d[], const word a[], size_t n, const word b[], size_t m, void* stack) { - // переменные в stack - word* prod = (word*)stack; - word* gcd = prod + n + m; - word* r = gcd + MIN2(n, m); - stack = r + MIN2(n, m); + word* prod; /* [n + m] */ + word* gcd; /* [MIN2(n, m)] */ + word* r; /* [MIN2(n, m)] */ // pre ASSERT(wwIsDisjoint2(a, n, d, MAX2(n, m))); ASSERT(wwIsDisjoint2(b, m, d, MAX2(n, m))); ASSERT(!wwIsZero(a, n) && !wwIsZero(b, m)); + // разметить стек + memSlice(stack, + zzLCM_local(n, m), SIZE_0, SIZE_MAX, + &prod, &gcd, &r, &stack); // d <- 0 wwSetZero(d, n + m); // нормализация @@ -180,25 +206,35 @@ void zzLCM(word d[], const word a[], size_t n, const word b[], size_t m, size_t zzLCM_deep(size_t n, size_t m) { - return O_OF_W(n + m + MIN2(n, m) + MIN2(n, m)) + + return memSliceSize( + zzLCM_local(n, m), utilMax(3, zzMul_deep(n, m), zzGCD_deep(n, m), - zzMod_deep(n + m, MIN2(n, m))); + zzMod_deep(n + m, MIN2(n, m))), + SIZE_MAX); } +#define zzExGCD_local(n, m)\ +/* aa */ O_OF_W(n),\ +/* bb */ O_OF_W(m),\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(m),\ +/* da1 */ O_OF_W(m),\ +/* db1 */ O_OF_W(n) + void zzExGCD(word d[], word da[], word db[], const word a[], size_t n, const word b[], size_t m, void* stack) { register size_t s; - register size_t nu, mv; - // переменные в stack - word* aa = (word*)stack; - word* bb = aa + n; - word* u = bb + m; - word* v = u + n; - word* da1 = v + m; - word* db1 = da1 + m; + register size_t nu; + register size_t mv; + word* aa; /* [n] */ + word* bb; /* [m] */ + word* u; /* [n] */ + word* v; /* [m] */ + word* da1; /* [m] */ + word* db1; /* [n] */ // pre ASSERT(wwIsDisjoint3(da, m, db, n, d, MIN2(n, m))); ASSERT(wwIsDisjoint2(a, n, d, MIN2(n, m))); @@ -208,6 +244,10 @@ void zzExGCD(word d[], word da[], word db[], const word a[], size_t n, ASSERT(wwIsDisjoint2(a, n, db, n)); ASSERT(wwIsDisjoint2(b, m, db, n)); ASSERT(!wwIsZero(a, n) && !wwIsZero(b, m)); + // разметить стек + memSlice(stack, + zzExGCD_local(n, m), SIZE_MAX, + &aa, &bb, &u, &v, &da1, &db1); // d <- 0, da <- 1, db <- 0, da1 <- 0, db1 <- 1 wwSetZero(d, MIN2(n, m)); wwSetW(da, m, 1); @@ -291,7 +331,9 @@ void zzExGCD(word d[], word da[], word db[], const word a[], size_t n, size_t zzExGCD_deep(size_t n, size_t m) { - return O_OF_W(3 * n + 3 * m); + return memSliceSize( + zzExGCD_local(n, m), + SIZE_MAX); } /* @@ -306,20 +348,30 @@ size_t zzExGCD_deep(size_t n, size_t m) ******************************************************************************* */ +#define zzDivMod_local(n)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(n),\ +/* da */ O_OF_W(n),\ +/* da1 */ O_OF_W(n) + void zzDivMod(word b[], const word divident[], const word a[], const word mod[], size_t n, void* stack) { - register size_t nu, nv; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; - word* da = v + n; - word* da1 = da + n; + register size_t nu; + register size_t nv; + word* u; /* [n] */ + word* v; /* [n] */ + word* da; /* [n] */ + word* da1; /* [n] */ // pre ASSERT(wwCmp(a, mod, n) < 0); ASSERT(wwCmp(divident, mod, n) < 0); ASSERT(wwIsDisjoint(b, mod, n)); ASSERT(zzIsOdd(mod, n) && mod[n - 1] != 0); + // разметить стек + memSlice(stack, + zzDivMod_local(n), SIZE_MAX, + &u, &v, &da, &da1); // da <- divident, da1 <- 0 wwCopy(da, divident, n); wwSetZero(da1, n); @@ -329,7 +381,7 @@ void zzDivMod(word b[], const word divident[], const word a[], nu = wwWordSize(u, n); nv = n; // итерации со следующими инвариантами: - // da * a = divident * u \mod mod + // da * a = divident * u \mod mod // da1 * a = -divident * v \mod mod while (!wwIsZero(v, nv)) { @@ -381,7 +433,9 @@ void zzDivMod(word b[], const word divident[], const word a[], size_t zzDivMod_deep(size_t n) { - return O_OF_W(4 * n); + return memSliceSize( + zzDivMod_local(n), + SIZE_MAX); } /* @@ -434,16 +488,26 @@ a и mod < 2^m, причем условие a < mod может нарушать ******************************************************************************* */ +#define zzAlmostInvMod_local(n)\ +/* u */ O_OF_W(n),\ +/* v */ O_OF_W(n),\ +/* da0 */ O_OF_W(n + 1),\ +/* da */ O_OF_W(n + 1) + size_t zzAlmostInvMod(word b[], const word a[], const word mod[], size_t n, void* stack) { register size_t k = 0; - size_t nu, nv; - // переменные в stack - word* u = (word*)stack; - word* v = u + n; - word* da0 = v + n; - word* da = da0 + n + 1; + size_t nu; + size_t nv; + word* u; /* [n] */ + word* v; /* [n] */ + word* da0; /* [n + 1] */ + word* da; /* [n + 1] */ + // разметить стек + memSlice(stack, + zzAlmostInvMod_local(n), SIZE_0, SIZE_MAX, + &u, &v, &da0, &da, &stack); // pre ASSERT(!wwIsZero(a, n)); ASSERT(wwCmp(a, mod, n) < 0); @@ -514,5 +578,7 @@ size_t zzAlmostInvMod(word b[], const word a[], const word mod[], size_t n, size_t zzAlmostInvMod_deep(size_t n) { - return O_OF_W(4 * n + 2); + return memSliceSize( + zzAlmostInvMod_local(n), + SIZE_MAX); } diff --git a/src/math/zz/zz_mod.c b/src/math/zz/zz_mod.c index f164449a..fac26e18 100644 --- a/src/math/zz/zz_mod.c +++ b/src/math/zz/zz_mod.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: modular arithmetic \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -20,8 +20,8 @@ ******************************************************************************* Модулярная арифметика: аддитивные операции -В первом проходе функции SAFE(zzAddMod)() выполняется сложение и -одновременно проверяется, не превосходит ли сумма модуль. Во втором проходе +В первом проходе регулярной редакции zzAddMod() выполняется сложение +и одновременно проверяется, не превосходит ли сумма модуль. Во втором проходе выполняется вычитание либо собственно модуля, либо нуля. Примерно так регуляризированы и другие функции. @@ -39,7 +39,7 @@ void FAST(zzAddMod)(word c[], const word a[], const word b[], const word mod[], zzSub2(c, mod, n); } -void SAFE(zzAddMod)(word c[], const word a[], const word b[], const word mod[], +void zzAddMod(word c[], const word a[], const word b[], const word mod[], size_t n) { register word carry = 0; @@ -81,8 +81,8 @@ void FAST(zzAddWMod)(word b[], const word a[], register word w, CLEAN(w); } -void SAFE(zzAddWMod)(word b[], const word a[], register word w, - const word mod[], size_t n) +void zzAddWMod(word b[], const word a[], register word w, const word mod[], + size_t n) { register word mask = 1; size_t i; @@ -117,7 +117,7 @@ void FAST(zzSubMod)(word c[], const word a[], const word b[], const word mod[], zzAdd2(c, mod, n); } -void SAFE(zzSubMod)(word c[], const word a[], const word b[], const word mod[], +void zzSubMod(word c[], const word a[], const word b[], const word mod[], size_t n) { register word mask = 0; @@ -143,8 +143,8 @@ void FAST(zzSubWMod)(word b[], const word a[], register word w, CLEAN(w); } -void SAFE(zzSubWMod)(word b[], const word a[], register word w, - const word mod[], size_t n) +void zzSubWMod(word b[], const word a[], register word w, const word mod[], + size_t n) { register word mask; ASSERT(wwIsSameOrDisjoint(a, b, n)); @@ -168,7 +168,7 @@ void FAST(zzNegMod)(word b[], const word a[], const word mod[], size_t n) wwSetZero(b, n); } -void SAFE(zzNegMod)(word b[], const word a[], const word mod[], size_t n) +void zzNegMod(word b[], const word a[], const word mod[], size_t n) { register word mask; ASSERT(wwIsSameOrDisjoint(a, b, n)); @@ -191,35 +191,47 @@ void SAFE(zzNegMod)(word b[], const word a[], const word mod[], size_t n) ******************************************************************************* */ +#define zzMulMod_local(n)\ +/* prod */ O_OF_W(2 * n) + void zzMulMod(word c[], const word a[], const word b[], const word mod[], size_t n, void* stack) { - word* prod = (word*)stack; - stack = prod + 2 * n; + word* prod; /* [2 * n] */ ASSERT(wwCmp(a, mod, n) < 0); ASSERT(wwCmp(b, mod, n) < 0); ASSERT(wwIsValid(c, n)); ASSERT(n > 0 && mod[n - 1] != 0); + memSlice(stack, + zzMulMod_local(n), SIZE_0, SIZE_MAX, + &prod, &stack); zzMul(prod, a, n, b, n, stack); zzMod(c, prod, 2 * n, mod, n, stack); } size_t zzMulMod_deep(size_t n) { - return O_OF_W(2 * n) + - utilMax(2, - zzMul_deep(n, n), - zzMod_deep(2 * n, n)); + return memSliceSize( + zzMulMod_local(n), + utilMax(2, + zzMul_deep(n, n), + zzMod_deep(2 * n, n)), + SIZE_MAX); } +#define zzMulWMod_local(n)\ +/* prod */ O_OF_W(n + 1) + void zzMulWMod(word b[], const word a[], register word w, const word mod[], size_t n, void* stack) { - word* prod = (word*)stack; - stack = prod + n + 1; + word* prod; /* [n + 1] */ ASSERT(wwCmp(a, mod, n) < 0); ASSERT(wwIsValid(b, n)); ASSERT(n > 0 && mod[n - 1] != 0); + memSlice(stack, + zzMulWMod_local(n), SIZE_0, SIZE_MAX, + &prod, &stack); prod[n] = zzMulW(prod, a, n, w); zzMod(b, prod, n + 1, mod, n, stack); CLEAN(w); @@ -227,42 +239,59 @@ void zzMulWMod(word b[], const word a[], register word w, const word mod[], size_t zzMulWMod_deep(size_t n) { - return O_OF_W(n + 1) + - zzMod_deep(n + 1, n); + return memSliceSize( + zzMulWMod_local(n), + zzMod_deep(n + 1, n), + SIZE_MAX); } +#define zzSqrMod_local(n)\ +/* sqr */ O_OF_W(2 * n) + void zzSqrMod(word b[], const word a[], const word mod[], size_t n, void* stack) { - word* sqr = (word*)stack; - stack = sqr + 2 * n; + word* sqr; /* [2 * n] */ ASSERT(wwCmp(a, mod, n) < 0); ASSERT(wwIsValid(b, n)); ASSERT(n > 0 && mod[n - 1] != 0); + memSlice(stack, + zzSqrMod_local(n), SIZE_0, SIZE_MAX, + &sqr, &stack); zzSqr(sqr, a, n, stack); zzMod(b, sqr, 2 * n, mod, n, stack); } size_t zzSqrMod_deep(size_t n) { - return O_OF_W(2 * n) + - utilMax(2, - zzSqr_deep(n), - zzMod_deep(2 * n, n)); + return memSliceSize( + zzSqrMod_local(n), + utilMax(2, + zzSqr_deep(n), + zzMod_deep(2 * n, n)), + SIZE_MAX); } +#define zzInvMod_local(n)\ +/* divident */ O_OF_W(n) + void zzInvMod(word b[], const word a[], const word mod[], size_t n, void* stack) { - word* divident = (word*)stack; - stack = divident + n; + word* divident; /* [n] */ + memSlice(stack, + zzInvMod_local(n), SIZE_0, SIZE_MAX, + ÷nt, &stack); wwSetW(divident, n, 1); zzDivMod(b, divident, a, mod, n, stack); } size_t zzInvMod_deep(size_t n) { - return O_OF_W(n) + zzDivMod_deep(n); + return memSliceSize( + zzInvMod_local(n), + zzDivMod_deep(n), + SIZE_MAX); } void FAST(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n) @@ -286,7 +315,7 @@ void FAST(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n) CLEAN2(hi, carry); } -void SAFE(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n) +void zzDoubleMod(word b[], const word a[], const word mod[], size_t n) { register word carry = 0; register word hi; @@ -342,7 +371,7 @@ void FAST(zzHalfMod)(word b[], const word a[], const word mod[], size_t n) CLEAN2(lo, carry); } -void SAFE(zzHalfMod)(word b[], const word a[], const word mod[], size_t n) +void zzHalfMod(word b[], const word a[], const word mod[], size_t n) { register word carry = 0; register word mask = 0; diff --git a/src/math/zz/zz_mul.c b/src/math/zz/zz_mul.c index 1fe9ed28..b73dda33 100644 --- a/src/math/zz/zz_mul.c +++ b/src/math/zz/zz_mul.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: multiplicative operations \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.09.13 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -225,7 +225,7 @@ word zzModW2(const word a[], size_t n, register word w) register word b; // pre ASSERT(w > 0); - ASSERT(w <= WORD_BIT_HALF); + ASSERT(w <= WORD_MID); ASSERT(wwIsValid(a, n)); // b <- B \mod mod b = (WORD_MAX - w + 1) % w; @@ -307,6 +307,11 @@ Vanstone S. Handbook of Applied Cryptography]: ******************************************************************************* */ +#define zzDiv_local(n, m)\ +/* divident */ O_OF_W(n + 1),\ +/* divisor */ O_OF_W(m),\ +/* mul */ O_OF_W(3) + void zzDiv(word q[], word r[], const word a[], size_t n, const word b[], size_t m, void* stack) { @@ -314,10 +319,9 @@ void zzDiv(word q[], word r[], const word a[], size_t n, const word b[], register size_t shift; register word t; size_t i; - // переменные в stack - word* divident; /*< нормализованное делимое (n + 1 слово) */ - word* divisor; /*< нормализованный делитель (m слов) */ - word* mul; /*< вспомогательное произведение (3 слова) */ + word* divident; /* [n + 1] нормализованное делимое */ + word* divisor; /* [m] нормализованный делитель */ + word* mul; /* [3] вспомогательное произведение */ // pre ASSERT(n >= m); ASSERT(wwIsValid(a, n) && wwIsValid(b, m)); @@ -338,10 +342,10 @@ void zzDiv(word q[], word r[], const word a[], size_t n, const word b[], r[0] = zzDivW(q, a, n, b[0]); return; } - // резервируем переменные в stack - divident = (word*)stack; - divisor = divident + n + 1; - mul = divisor + m; + // разметить стек + memSlice(stack, + zzDiv_local(n, m), SIZE_MAX, + ÷nt, &divisor, &mul); // divident <- a wwCopy(divident, a, n); divident[n] = 0; @@ -394,19 +398,26 @@ void zzDiv(word q[], word r[], const word a[], size_t n, const word b[], size_t zzDiv_deep(size_t n, size_t m) { - return O_OF_W(n + m + 4); + return memSliceSize( + zzDiv_local(n, m), + SIZE_MAX); } -void zzMod(word r[], const word a[], size_t n, const word b[], size_t m, void* stack) +#define zzMod_local(n, m)\ +/* divident */ O_OF_W(n + 1),\ +/* divisor */ O_OF_W(m),\ +/* mul */ O_OF_W(3) + +void zzMod(word r[], const word a[], size_t n, const word b[], size_t m, +void* stack) { register dword qhat; register size_t shift; register word t; size_t i; - // переменные в stack - word* divident; /*< нормализованное делимое (n + 1 слово) */ - word* divisor; /*< нормализованный делитель (m слов) */ - word* mul; /*< вспомогательное произведение (3 слова) */ + word* divident; /*< [n + 1] нормализованное делимое */ + word* divisor; /*< [m] нормализованный делитель */ + word* mul; /*< [3] вспомогательное произведение */ // pre ASSERT(wwIsValid(a, n) && wwIsValid(b, m)); ASSERT(m > 0 && b[m - 1] > 0); @@ -426,10 +437,10 @@ void zzMod(word r[], const word a[], size_t n, const word b[], size_t m, void* s r[0] = zzModW(a, n, b[0]); return; } - // резервируем переменные в stack - divident = (word*)stack; - divisor = divident + n + 1; - mul = divisor + m; + // разметить стек + memSlice(stack, + zzMod_local(n, m), SIZE_MAX, + ÷nt, &divisor, &mul); // divident <- a wwCopy(divident, a, n); divident[n] = 0; @@ -478,5 +489,7 @@ void zzMod(word r[], const word a[], size_t n, const word b[], size_t m, void* s size_t zzMod_deep(size_t n, size_t m) { - return O_OF_W(n + m + 4); + return memSliceSize( + zzMod_local(n, m), + SIZE_MAX); } diff --git a/src/math/zz/zz_pow.c b/src/math/zz/zz_pow.c index d1c59ebf..5e196198 100644 --- a/src/math/zz/zz_pow.c +++ b/src/math/zz/zz_pow.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: modular exponentiation \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.06.10 +\version 2025.09.13 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -22,22 +22,25 @@ ******************************************************************************* */ +#define zzPowerMod_local(n, no)\ +/* t */ O_OF_W(n + 1),\ +/* r */ zmCreate_keep(no) + void zzPowerMod(word c[], const word a[], size_t n, const word b[], size_t m, const word mod[], void* stack) { size_t no; - // переменные в stack - word* t; - qr_o* r; + word* t; /* [n] */ + qr_o* r; /* [zmCreate_keep(no)] */ // pre ASSERT(n > 0 && mod[n - 1] != 0); ASSERT(wwCmp(a, mod, n) < 0); // размерности no = wwOctetSize(mod, n); - // раскладка stack - t = (word*)stack; - r = (qr_o*)(t + n); - stack = (octet*)r + zmCreate_keep(no); + // разметить стек + memSlice(stack, + zzPowerMod_local(n, no), SIZE_0, SIZE_MAX, + &t, &r, &stack); // r <- Zm(mod) wwTo(t, no, mod); zmCreate(r, (octet*)t, no, stack); @@ -55,10 +58,12 @@ size_t zzPowerMod_deep(size_t n, size_t m) { const size_t no = O_OF_W(n); const size_t r_deep = zmCreate_deep(no); - return no + + return memSliceSize( + zzPowerMod_local(n, m), utilMax(2, r_deep, - qrPower_deep(n, m, r_deep)); + qrPower_deep(n, m, r_deep)), + SIZE_MAX); } /* @@ -69,6 +74,9 @@ size_t zzPowerMod_deep(size_t n, size_t m) ******************************************************************************* */ +#define zzPowerModW_local()\ +/* powers */ O_OF_W(4) + word zzPowerModW(register word a, register word b, register word mod, void* stack) { @@ -76,15 +84,16 @@ word zzPowerModW(register word a, register word b, register word mod, register word slide; register size_t pos; register size_t slide_size; - // переменные в stack - word* powers; /* [4]powers */ + word* powers; /* [4] */ // pre ASSERT(mod != 0); // b == 0? if (b == 0) return 1; - // раскладка stack - powers = (word*)stack; + // разметить стек + memSlice(stack, + zzPowerModW_local(), SIZE_MAX, + &powers); // powers <- малые нечетные степени a prod = a; prod *= a, prod %= mod, powers[0] = (word)prod; @@ -136,5 +145,7 @@ word zzPowerModW(register word a, register word b, register word mod, size_t zzPowerModW_deep() { - return O_OF_W(4); + return memSliceSize( + zzPowerModW_local(), + SIZE_MAX); } diff --git a/src/math/zz/zz_red.c b/src/math/zz/zz_red.c index f05b2b85..37788cd5 100644 --- a/src/math/zz/zz_red.c +++ b/src/math/zz/zz_red.c @@ -4,7 +4,7 @@ \brief Multiple-precision unsigned integers: modular reductions \project bee2 [cryptographic library] \created 2012.04.22 -\version 2025.05.07 +\version 2025.09.26 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -68,7 +68,7 @@ void FAST(zzRedCrand)(word a[], const word mod[], size_t n, void* stack) CLEAN2(prod, carry); } -void SAFE(zzRedCrand)(word a[], const word mod[], size_t n, void* stack) +void zzRedCrand(word a[], const word mod[], size_t n, void* stack) { register word carry; register dword prod; @@ -123,14 +123,20 @@ size_t zzRedCrand_deep(size_t n) ******************************************************************************* */ +#define zzRedBarrStart_local(n)\ +/* divident */ O_OF_W(2 * n + 1) + void zzRedBarrStart(word barr_param[], const word mod[], size_t n, void* stack) { - word* divident = (word*)stack; - stack = divident + 2 * n + 1; + word* divident; /* [2 * n + 1] */ // pre ASSERT(wwIsDisjoint2(barr_param, n + 2, mod, n)); ASSERT(n > 0 && mod[n - 1] != 0); + // разметить стек + memSlice(stack, + zzRedBarrStart_local(n), SIZE_0, SIZE_MAX, + ÷nt, &stack); // divident <- B^{2n} wwSetZero(divident, 2 * n); divident[2 * n] = 1; @@ -140,20 +146,29 @@ void zzRedBarrStart(word barr_param[], const word mod[], size_t n, size_t zzRedBarrStart_deep(size_t n) { - return O_OF_W(2 * n + 1) + zzDiv_deep(2 * n + 1, n); + return memSliceSize( + zzRedBarrStart_local(n), + zzDiv_deep(2 * n + 1, n), + SIZE_MAX); } +#define zzRedBarr_local(n)\ +/* q */ O_OF_W(2 * n + 3),\ +/* qm */ O_OF_W(2 * n + 2) + void FAST(zzRedBarr)(word a[], const word mod[], size_t n, const word barr_param[], void* stack) { - // переменные в stack - word* q = (word*)stack; - word* qm = q + (n + 1) + (n + 2); - stack = qm + (n + 2) + n; + word* q; /* [(n + 1) + (n + 2)] */ + word* qm; /* [(n + 2) + n] */ // pre ASSERT(wwIsDisjoint2(a, 2 * n, mod, n)); ASSERT(wwIsDisjoint2(a, 2 * n, barr_param, n + 2)); ASSERT(n > 0 && mod[n - 1] != 0); + // разметить стек + memSlice(stack, + zzRedBarr_local(n), SIZE_0, SIZE_MAX, + &q, &qm, &stack); // q <- (a \div B^{n - 1}) * barr_param zzMul(q, a + n - 1, n + 1, barr_param, n + 2, stack); // qm <- (q \div B^{n + 1}) * mod @@ -165,19 +180,21 @@ void FAST(zzRedBarr)(word a[], const word mod[], size_t n, a[n] -= zzSub2(a, mod, n); } -void SAFE(zzRedBarr)(word a[], const word mod[], size_t n, +void zzRedBarr(word a[], const word mod[], size_t n, const word barr_param[], void* stack) { register word w; size_t i; - // переменные в stack - word* q = (word*)stack; - word* qm = q + (n + 1) + (n + 2); - stack = qm + (n + 2) + n; + word* q; /* [(n + 1) + (n + 2)] */ + word* qm; /* [(n + 2) + n] */ // pre ASSERT(wwIsDisjoint2(a, 2 * n, mod, n)); ASSERT(wwIsDisjoint2(a, 2 * n, barr_param, n + 2)); ASSERT(n > 0 && mod[n - 1] != 0); + // разметить стек + memSlice(stack, + zzRedBarr_local(n), SIZE_0, SIZE_MAX, + &q, &qm, &stack); // q <- (a \div B^{n - 1}) * barr_param zzMul(q, a + n - 1, n + 1, barr_param, n + 2, stack); // qm <- (q \div B^{n + 1}) * mod @@ -206,10 +223,12 @@ void SAFE(zzRedBarr)(word a[], const word mod[], size_t n, size_t zzRedBarr_deep(size_t n) { - return O_OF_W(4 * n + 5) + - utilMax(2, - zzMul_deep(n + 1, n + 2), - zzMul_deep(n + 2, n)); + return memSliceSize( + zzRedBarr_local(n), + utilMax(2, + zzMul_deep(n + 1, n + 2), + zzMul_deep(n + 2, n)), + SIZE_MAX); } /* @@ -257,8 +276,8 @@ void FAST(zzRedMont)(word a[], const word mod[], size_t n, CLEAN2(carry, w); } -void SAFE(zzRedMont)(word a[], const word mod[], size_t n, - register word mont_param, void* stack) +void zzRedMont(word a[], const word mod[], size_t n, register word mont_param, + void* stack) { register word carry = 0; register word w = 0; @@ -294,7 +313,7 @@ size_t zzRedMont_deep(size_t n) /* ******************************************************************************* -Редукция Крэндалла-Монтгомери +Редукция Крендалла-Монтгомери Редукция Монтгомери для модуля mod = B^n - c, 0 < c < B, n >= 2, упрощается: [pretime] m* <- c^{-1} \bmod B @@ -350,7 +369,7 @@ void FAST(zzRedCrandMont)(word a[], const word mod[], size_t n, CLEAN(prod), CLEAN3(carry, borrow, w); } -void SAFE(zzRedCrandMont)(word a[], const word mod[], size_t n, +void zzRedCrandMont(word a[], const word mod[], size_t n, register word mont_param, void* stack) { register word carry = 0; diff --git a/test/core/apdu_test.c b/test/core/apdu_test.c index b1e9a983..b658d2d4 100644 --- a/test/core/apdu_test.c +++ b/test/core/apdu_test.c @@ -4,7 +4,7 @@ \brief Tests for APDU formats \project bee2/test \created 2022.10.31 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -22,16 +22,28 @@ ******************************************************************************* */ +#define apduTest_local()\ +/* cmd */ sizeof(apdu_cmd_t) + 257,\ +/* resp */ (sizeof(apdu_resp_t) + 20) | SIZE_HI,\ +/* cmd1 */ sizeof(apdu_cmd_t) + 257,\ +/* resp1 */ (sizeof(apdu_resp_t) + 20) | SIZE_HI + bool_t apduTest() { - octet stack[2048]; - apdu_cmd_t* cmd = (apdu_cmd_t*)stack; - apdu_cmd_t* cmd1 = (apdu_cmd_t*)(stack + 1024); - apdu_resp_t* resp = (apdu_resp_t*)stack; - apdu_resp_t* resp1 = (apdu_resp_t*)(stack + 1024); + mem_align_t state[2048 / sizeof(mem_align_t)]; + apdu_cmd_t* cmd; /* sizeof(apdu_cmd_t) + 257 */ + apdu_resp_t* resp; /* sizeof(apdu_resp_t) + 20 (|cmd) */ + apdu_cmd_t* cmd1; /* sizeof(apdu_cmd_t) + 257 */ + apdu_resp_t* resp1; /* sizeof(apdu_resp_t) + 20 (|cmd1) */ octet apdu[1024]; size_t count; size_t count1; + // разметить состояние + if (sizeof(state) < memSliceSize(apduTest_local(), SIZE_MAX)) + return FALSE; + memSlice(state, + apduTest_local(), SIZE_MAX, + &cmd, &resp, &cmd1, &resp1); // cmd: точечный тест memSetZero(cmd, sizeof(apdu_cmd_t)); cmd->cla = 0x00, cmd->ins = 0xA4, cmd->p1 = 0x04, cmd->p2 = 0x04; @@ -44,8 +56,7 @@ bool_t apduTest() !hexEq(apdu, "00A40404045465737400")) return FALSE; count1 = apduCmdDec(0, apdu, count); - if (count1 > sizeof(stack) / 2 || - count1 != sizeof(apdu_cmd_t) + 4 || + if (count1 != sizeof(apdu_cmd_t) + 4 || apduCmdDec(cmd1, apdu, count) != count1 || !memEq(cmd, cmd1, count1)) return FALSE; @@ -60,15 +71,14 @@ bool_t apduTest() apduCmdEnc(apdu, cmd) != count) return FALSE; count1 = apduCmdDec(0, apdu, count); - if (count1 > sizeof(stack) / 2 || - apduCmdDec(cmd1, apdu, count) != count1 || + if (apduCmdDec(cmd1, apdu, count) != count1 || !memEq(cmd, cmd1, count1)) return FALSE; } // resp: точечный тест memSetZero(resp, sizeof(apdu_resp_t)); resp->sw1 = 0x90, resp->sw2 = 0x00; - cmd->rdf_len = 20; + resp->rdf_len = 20; hexTo(resp->rdf, "E012C00401FF8010C00402FF8010C00403FF8010"); count = apduRespEnc(0, resp); if (count > sizeof(apdu) || @@ -77,8 +87,7 @@ bool_t apduTest() !hexEq(apdu, "E012C00401FF8010C00402FF8010C00403FF80109000")) return FALSE; count1 = apduRespDec(0, apdu, count); - if (count1 > sizeof(stack) / 2 || - count1 != sizeof(apdu_resp_t) + 20 || + if (count1 != sizeof(apdu_resp_t) + 20 || apduRespDec(resp1, apdu, count) != count1 || !memEq(resp, resp1, count1)) return FALSE; diff --git a/test/core/blob_test.c b/test/core/blob_test.c index 284c2738..e6cf7c7b 100644 --- a/test/core/blob_test.c +++ b/test/core/blob_test.c @@ -4,7 +4,7 @@ \brief Tests for blob functions \project bee2/test \created 2023.03.21 -\version 2023.03.23 +\version 2025.09.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -23,6 +23,7 @@ bool_t blobTest() { blob_t b1 = 0; blob_t b2 = 0; + blob_t b3 = 0; // create / resize b1 = blobCreate(123); b2 = blobResize(b2, 120); @@ -54,7 +55,28 @@ bool_t blobTest() blobClose(b2), blobClose(b1); return FALSE; } + // slice + { + void* p; + void* p1; + void* p2; + b3 = blobCreate2( + (size_t)11, + (size_t)10, + (size_t)32 | SIZE_HI, + SIZE_MAX, + &p, &p1, &p2); + if (!b3 || + !memIsAligned(b3, sizeof(mem_align_t)) || + !memIsAligned(p1, sizeof(mem_align_t)) || + b3 != p || p == p1 || p1 != p2) + { + blobClose(b3); + return FALSE; + } + } // wipe / close + blobClose(b3); blobWipe(b2); blobClose(b2); blobClose(b1); diff --git a/test/core/mem_test.c b/test/core/mem_test.c index de955a0b..1fcfa84f 100644 --- a/test/core/mem_test.c +++ b/test/core/mem_test.c @@ -4,7 +4,7 @@ \brief Tests for memory functions \project bee2/test \created 2014.02.01 -\version 2023.03.06 +\version 2025.09.23 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -32,8 +32,11 @@ bool_t memTest() octet buf[16]; octet buf1[16]; octet buf2[16]; + mem_align_t buf3[3]; void* p; void* p1; + void* p2; + void* p3; size_t i; // pre CASSERT(sizeof(buf) == sizeof(buf1)); @@ -76,44 +79,44 @@ bool_t memTest() // сравнение hexTo(buf, "000102030405060708090A0B0C0D0E0F"); hexTo(buf1, "F00102030405060708090A0B0C0D0EFF"); - if (SAFE(memIsZero)(buf, 15) || + if (memIsZero(buf, 15) || FAST(memIsZero)(buf, 15) || FAST(memIsZero)(buf, 3) || - SAFE(memEq)(buf + 1, buf1 + 1, 15) || + memEq(buf + 1, buf1 + 1, 15) || FAST(memEq)(buf + 1, buf1 + 1, 15) || - SAFE(memEq)(buf + 8, buf1 + 8, 8) || + memEq(buf + 8, buf1 + 8, 8) || FAST(memEq)(buf + 8, buf1 + 8, 8) || - !SAFE(memEq)(buf + 1, buf1 + 1, 8) || + !memEq(buf + 1, buf1 + 1, 8) || !FAST(memEq)(buf + 1, buf1 + 1, 8) || - !SAFE(memEq)(buf + 1, buf1 + 1, 14) || + !memEq(buf + 1, buf1 + 1, 14) || !FAST(memEq)(buf + 1, buf1 + 1, 14) || - SAFE(memCmp)(buf, buf1, 7) != -1 || + memCmp(buf, buf1, 7) != -1 || FAST(memCmp)(buf, buf1, 7) != -1 || - SAFE(memCmpRev)(buf, buf1, 7) != -1 || + memCmpRev(buf, buf1, 7) != -1 || FAST(memCmpRev)(buf, buf1, 7) != -1 || - SAFE(memCmp)(buf, buf1, 15) != -1 || + memCmp(buf, buf1, 15) != -1 || FAST(memCmp)(buf, buf1, 15) != -1 || - SAFE(memCmpRev)(buf, buf1, 15) != -1 || + memCmpRev(buf, buf1, 15) != -1 || FAST(memCmpRev)(buf, buf1, 15) != -1 || - SAFE(memCmp)(buf1, buf, 15) != 1 || + memCmp(buf1, buf, 15) != 1 || FAST(memCmp)(buf1, buf, 15) != 1 || - SAFE(memCmpRev)(buf1, buf, 15) != 1 || + memCmpRev(buf1, buf, 15) != 1 || FAST(memCmpRev)(buf1, buf, 15) != 1 || - SAFE(memCmp)(buf, buf1, 8) != -1 || + memCmp(buf, buf1, 8) != -1 || FAST(memCmp)(buf, buf1, 8) != -1 || - SAFE(memCmpRev)(buf, buf1, 8) != -1 || + memCmpRev(buf, buf1, 8) != -1 || FAST(memCmpRev)(buf, buf1, 8) != -1 || - SAFE(memCmp)(buf1, buf, 8) != 1 || + memCmp(buf1, buf, 8) != 1 || FAST(memCmp)(buf1, buf, 8) != 1 || - SAFE(memCmpRev)(buf1, buf, 8) != 1 || + memCmpRev(buf1, buf, 8) != 1 || FAST(memCmpRev)(buf1, buf, 8) != 1 || - SAFE(memCmp)(buf + 1, buf1 + 1, 8) != 0 || + memCmp(buf + 1, buf1 + 1, 8) != 0 || FAST(memCmp)(buf + 1, buf1 + 1, 8) != 0 || - SAFE(memCmp)(buf + 1, buf1 + 1, 14) != 0 || + memCmp(buf + 1, buf1 + 1, 14) != 0 || FAST(memCmp)(buf + 1, buf1 + 1, 14) != 0 || - SAFE(memCmpRev)(buf + 1, buf1 + 1, 8) != 0 || + memCmpRev(buf + 1, buf1 + 1, 8) != 0 || FAST(memCmpRev)(buf + 1, buf1 + 1, 8) != 0 || - SAFE(memCmpRev)(buf + 1, buf1 + 1, 14) != 0 || + memCmpRev(buf + 1, buf1 + 1, 14) != 0 || FAST(memCmpRev)(buf + 1, buf1 + 1, 14) != 0) return FALSE; memRev(buf, 15); @@ -121,23 +124,23 @@ bool_t memTest() return FALSE; hexTo(buf, "F001020304050607"); hexTo(buf1, "00010203040506F7"); - if (SAFE(memCmp)(buf, buf1, 8) != 1 || + if (memCmp(buf, buf1, 8) != 1 || FAST(memCmp)(buf, buf1, 8) != 1 || - SAFE(memCmp)(buf1, buf, 8) != -1 || + memCmp(buf1, buf, 8) != -1 || FAST(memCmp)(buf1, buf, 8) != -1 || - SAFE(memCmpRev)(buf, buf1, 8) != -1 || + memCmpRev(buf, buf1, 8) != -1 || FAST(memCmpRev)(buf, buf1, 8) != -1 || - SAFE(memCmpRev)(buf1, buf, 8) != 1 || + memCmpRev(buf1, buf, 8) != 1 || FAST(memCmpRev)(buf1, buf, 8) != 1) return FALSE; hexTo(buf, "01010101010101010102"); - if (SAFE(memIsRep)(buf, 7, 0x01) != TRUE || + if (memIsRep(buf, 7, 0x01) != TRUE || FAST(memIsRep)(buf, 7, 0x01) != TRUE || - SAFE(memIsRep)(buf, 8, 0x01) != TRUE || + memIsRep(buf, 8, 0x01) != TRUE || FAST(memIsRep)(buf, 8, 0x01) != TRUE || - SAFE(memIsRep)(buf, 9, 0x01) != TRUE || + memIsRep(buf, 9, 0x01) != TRUE || FAST(memIsRep)(buf, 9, 0x01) != TRUE || - SAFE(memIsRep)(buf, 10, 0x01) == TRUE || + memIsRep(buf, 10, 0x01) == TRUE || FAST(memIsRep)(buf, 10, 0x01) == TRUE) return FALSE; // join @@ -167,6 +170,36 @@ bool_t memTest() memXor2(buf2, buf, 8); if (!memIsRep(buf2, 8, 0) || buf2[8] != 0x08) return FALSE; + // разметка #1 + if (memSliceSize( + SIZE_1, SIZE_1 | SIZE_HI, SIZE_1, SIZE_1, SIZE_MAX) != + 2 * sizeof(mem_align_t) + 1) + return FALSE; + memSlice(buf3, + SIZE_1, SIZE_1 | SIZE_HI, SIZE_0, SIZE_0, SIZE_MAX, + &p, &p1, &p2, &p3); + if (p != buf3 || p1 != p || p2 == p1 || p3 != p2 || + p2 != memSliceNext(p1, SIZE_1) || p2 != memSliceNext2(p1, SIZE_1)) + return FALSE; + // разметка #2 + if (memSliceSize( + SIZE_1 | SIZE_HI, SIZE_1 | SIZE_HI, SIZE_MAX) != 1) + return FALSE; + memSlice(buf3, + SIZE_1 | SIZE_HI, SIZE_1 | SIZE_HI, SIZE_MAX, + &p, &p1); + if (p != buf3 || p1 != p) + return FALSE; + // разметка #3 + if (memSliceSize( + SIZE_1, SIZE_1 | SIZE_HI, SIZE_1 | SIZE_HI, SIZE_1, SIZE_MAX, + &p, &p1, &p2, &p3) != sizeof(mem_align_t) + 1) + return FALSE; + memSlice(buf3, + SIZE_1, SIZE_1 | SIZE_HI, SIZE_1 | SIZE_HI, SIZE_1, SIZE_MAX, + &p, &p1, &p2, &p3); + if (p != buf3 || p1 != p || p2 != p || p3 == p2) + return FALSE; // все нормально return TRUE; } diff --git a/test/core/prng_test.c b/test/core/prng_test.c index 50f620cd..7afe4eea 100644 --- a/test/core/prng_test.c +++ b/test/core/prng_test.c @@ -4,13 +4,14 @@ \brief Tests for pseudorandom number generators \project bee2/test \created 2014.06.30 -\version 2025.05.07 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ #include +#include #include /* @@ -22,7 +23,7 @@ bool_t prngTest() { octet buf[128]; - char state[256]; + mem_align_t state[256 / sizeof(mem_align_t)]; // подготовить память if (sizeof(state) < prngSTB_keep()) return FALSE; diff --git a/test/core/u16_test.c b/test/core/u16_test.c index c5d53b0f..e67823eb 100644 --- a/test/core/u16_test.c +++ b/test/core/u16_test.c @@ -4,7 +4,7 @@ \brief Tests for operations on 16-bit words \project bee2/test \created 2017.01.11 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -47,12 +47,12 @@ bool_t u16Test() u16Weight(0xFFF8) != 13) return FALSE; // CTZ / CLZ - if (SAFE(u16CTZ)(0) != 16 || FAST(u16CTZ)(0) != 16 || - SAFE(u16CLZ)(0) != 16 || FAST(u16CLZ)(0) != 16 || - SAFE(u16CTZ)(1) != 0 || FAST(u16CTZ)(1) != 0 || - SAFE(u16CLZ)(1) != 15 || FAST(u16CLZ)(1) != 15 || - SAFE(u16CTZ)(0xFFF8) != 3 || FAST(u16CTZ)(0xFFF8) != 3 || - SAFE(u16CLZ)(0xFFF8) != 0 || FAST(u16CLZ)(0xFFF8) != 0 + if (u16CTZ(0) != 16 || FAST(u16CTZ)(0) != 16 || + u16CLZ(0) != 16 || FAST(u16CLZ)(0) != 16 || + u16CTZ(1) != 0 || FAST(u16CTZ)(1) != 0 || + u16CLZ(1) != 15 || FAST(u16CLZ)(1) != 15 || + u16CTZ(0xFFF8) != 3 || FAST(u16CTZ)(0xFFF8) != 3 || + u16CLZ(0xFFF8) != 0 || FAST(u16CLZ)(0xFFF8) != 0 ) return FALSE; // shuffle diff --git a/test/core/u32_test.c b/test/core/u32_test.c index 327c32ef..d1784ae6 100644 --- a/test/core/u32_test.c +++ b/test/core/u32_test.c @@ -4,7 +4,7 @@ \brief Tests for operations on 32-bit words \project bee2/test \created 2017.01.11 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -49,14 +49,14 @@ bool_t u32Test() u32Weight(0xFFFFFFFF) != 32 || u32Parity(0xFFFFFFFF)) return FALSE; // CTZ / CLZ - if (SAFE(u32CTZ)(0) != 32 || FAST(u32CTZ)(0) != 32 || - SAFE(u32CLZ)(0) != 32 || FAST(u32CLZ)(0) != 32 || - SAFE(u32CTZ)(1) != 0 || FAST(u32CTZ)(1) != 0 || - SAFE(u32CLZ)(1) != 31 || FAST(u32CLZ)(1) != 31 || - SAFE(u32CTZ)(0xFFF8) != 3 || FAST(u32CTZ)(0xFFF8) != 3 || - SAFE(u32CLZ)(0xFFF8) != 16 || FAST(u32CLZ)(0xFFF8) != 16 || - SAFE(u32CTZ)(0x7FFFE000) != 13 || FAST(u32CTZ)(0x7FFFE000) != 13 || - SAFE(u32CLZ)(0x7FFFE000) != 1 || FAST(u32CLZ)(0x7FFFE000) != 1) + if (u32CTZ(0) != 32 || FAST(u32CTZ)(0) != 32 || + u32CLZ(0) != 32 || FAST(u32CLZ)(0) != 32 || + u32CTZ(1) != 0 || FAST(u32CTZ)(1) != 0 || + u32CLZ(1) != 31 || FAST(u32CLZ)(1) != 31 || + u32CTZ(0xFFF8) != 3 || FAST(u32CTZ)(0xFFF8) != 3 || + u32CLZ(0xFFF8) != 16 || FAST(u32CLZ)(0xFFF8) != 16 || + u32CTZ(0x7FFFE000) != 13 || FAST(u32CTZ)(0x7FFFE000) != 13 || + u32CLZ(0x7FFFE000) != 1 || FAST(u32CLZ)(0x7FFFE000) != 1) return FALSE; // shuffle if (u32Deshuffle(0) != 0 || u32Deshuffle(1) != 1 || diff --git a/test/core/u64_test.c b/test/core/u64_test.c index c3ce7d7d..6eb7923e 100644 --- a/test/core/u64_test.c +++ b/test/core/u64_test.c @@ -4,7 +4,7 @@ \brief Tests for operations on 64-bit words \project bee2/test \created 2017.01.11 -\version 2024.11.18 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -56,17 +56,17 @@ bool_t u64Test() u64Parity(0xFFFFFFFFFFFFFFFF)) return FALSE; // CTZ / CLZ - if (SAFE(u64CTZ)(0) != 64 || FAST(u64CTZ)(0) != 64 || - SAFE(u64CLZ)(0) != 64 || FAST(u64CLZ)(0) != 64 || - SAFE(u64CTZ)(1) != 0 || FAST(u64CTZ)(1) != 0 || - SAFE(u64CLZ)(1) != 63 || FAST(u64CLZ)(1) != 63 || - SAFE(u64CTZ)(0xFFF8) != 3 || FAST(u64CTZ)(0xFFF8) != 3 || - SAFE(u64CLZ)(0xFFF8) != 48 || FAST(u64CLZ)(0xFFF8) != 48 || - SAFE(u64CTZ)(0x7FFFE000) != 13 || FAST(u64CTZ)(0x7FFFE000) != 13 || - SAFE(u64CLZ)(0x7FFFE000) != 33 || FAST(u64CLZ)(0x7FFFE000) != 33 || - SAFE(u64CTZ)(0x0000003FFDDF8000) != 15 || + if (u64CTZ(0) != 64 || FAST(u64CTZ)(0) != 64 || + u64CLZ(0) != 64 || FAST(u64CLZ)(0) != 64 || + u64CTZ(1) != 0 || FAST(u64CTZ)(1) != 0 || + u64CLZ(1) != 63 || FAST(u64CLZ)(1) != 63 || + u64CTZ(0xFFF8) != 3 || FAST(u64CTZ)(0xFFF8) != 3 || + u64CLZ(0xFFF8) != 48 || FAST(u64CLZ)(0xFFF8) != 48 || + u64CTZ(0x7FFFE000) != 13 || FAST(u64CTZ)(0x7FFFE000) != 13 || + u64CLZ(0x7FFFE000) != 33 || FAST(u64CLZ)(0x7FFFE000) != 33 || + u64CTZ(0x0000003FFDDF8000) != 15 || FAST(u64CTZ)(0x0000003FFDDF8000) != 15 || - SAFE(u64CLZ)(0x0000003FFDDF8000) != 26 || + u64CLZ(0x0000003FFDDF8000) != 26 || FAST(u64CLZ)(0x0000003FFDDF8000) != 26) return FALSE; // shuffle diff --git a/test/core/util_test.c b/test/core/util_test.c index d7d30860..3b856887 100644 --- a/test/core/util_test.c +++ b/test/core/util_test.c @@ -4,7 +4,7 @@ \brief Tests for utilities \project bee2/test \created 2017.01.17 -\version 2025.06.11 +\version 2025.09.05 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -62,14 +62,19 @@ static void destroy2() bool_t utilTest() { + // версия printf("utilVersion: %s [%s]\n", utilVersion(), utilInfo()); - if (utilMin(5, SIZE_1, (size_t)2, (size_t)3, SIZE_1, SIZE_0) != 0 || - utilMax(5, SIZE_1, (size_t)2, (size_t)3, SIZE_1, SIZE_0) != 3) - return FALSE; // деструкторы if (!utilOnExit(destroy1) || !utilOnExit(destroy2) || !utilOnExit(destroy2) || !utilOnExit(destroy2)) return FALSE; + // min / max + if (utilMin(5, SIZE_1, (size_t)2, (size_t)3, SIZE_1, SIZE_0) != 0 || + utilMax(5, SIZE_1, (size_t)2, (size_t)3, SIZE_1, SIZE_0) != 3) + return FALSE; + // выравнивание + if (utilAlign(10, 5) != 10 || utilAlign(11, 5) != 15) + return FALSE; // контрольные суммы if (utilCRC32("123456789", 9, 0) != 0xCBF43926) return FALSE; diff --git a/test/crypto/bake_test.c b/test/crypto/bake_test.c index 754edcd9..c8ad7ddc 100644 --- a/test/crypto/bake_test.c +++ b/test/crypto/bake_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.66 (bake) \project bee2/test \created 2014.04.23 -\version 2025.04.25 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -302,8 +302,8 @@ bool_t bakeTest() bign_params params[1]; octet randa[48]; octet randb[48]; - octet echoa[64]; - octet echob[64]; + mem_align_t statea[64 / sizeof(mem_align_t)]; + mem_align_t stateb[64 / sizeof(mem_align_t)]; bake_settings settingsa[1]; bake_settings settingsb[1]; octet da[32]; @@ -320,7 +320,8 @@ bool_t bakeTest() octet secret[32]; octet iv[64]; // подготовить память - if (sizeof(echoa) < prngEcho_keep()) + if (sizeof(statea) < prngEcho_keep() || + sizeof(stateb) < prngEcho_keep()) return FALSE; // загрузить долговременные параметры if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1") != ERR_OK) @@ -331,8 +332,8 @@ bool_t bakeTest() settingsa->kca = settingsa->kcb = TRUE; settingsb->kca = settingsb->kcb = TRUE; settingsa->rng = settingsb->rng = prngEchoStepR; - settingsa->rng_state = echoa; - settingsb->rng_state = echob; + settingsa->rng_state = statea; + settingsb->rng_state = stateb; // загрузить личные ключи hexTo(da, _da); hexTo(db, _db); @@ -352,8 +353,8 @@ bool_t bakeTest() { filea->i = filea->offset = 0; fileb->i = fileb->offset = 0; - prngEchoStart(echoa, randa, strLen(_bmqv_randb) / 2); - prngEchoStart(echob, randb, strLen(_bmqv_randb) / 2); + prngEchoStart(statea, randa, strLen(_bmqv_randb) / 2); + prngEchoStart(stateb, randb, strLen(_bmqv_randb) / 2); codeb = bakeBMQVRunB(keyb, params, settingsb, db, certb, certa, fileMsgRead, fileMsgWrite, fileb); if (codeb != ERR_OK && codeb != ERR_FILE_NOT_FOUND) @@ -381,8 +382,8 @@ bool_t bakeTest() { filea->i = filea->offset = 0; fileb->i = fileb->offset = 0; - prngEchoStart(echoa, randa, strLen(_bsts_randb) / 2); - prngEchoStart(echob, randb, strLen(_bsts_randb) / 2); + prngEchoStart(statea, randa, strLen(_bsts_randb) / 2); + prngEchoStart(stateb, randb, strLen(_bsts_randb) / 2); codeb = bakeBSTSRunB(keyb, params, settingsb, db, certb, bakeTestCertVal, fileMsgRead, fileMsgWrite, fileb); if (codeb != ERR_OK && codeb != ERR_FILE_NOT_FOUND) @@ -410,8 +411,8 @@ bool_t bakeTest() { filea->i = filea->offset = 0; fileb->i = fileb->offset = 0; - prngEchoStart(echoa, randa, strLen(_bpace_randb) / 2); - prngEchoStart(echob, randb, strLen(_bpace_randb) / 2); + prngEchoStart(statea, randa, strLen(_bpace_randb) / 2); + prngEchoStart(stateb, randb, strLen(_bpace_randb) / 2); codeb = bakeBPACERunB(keyb, params, settingsb, (const octet*)pwd, strLen(pwd), fileMsgRead, fileMsgWrite, fileb); if (codeb != ERR_OK && codeb != ERR_FILE_NOT_FOUND) @@ -427,7 +428,7 @@ bool_t bakeTest() "DAC4D8F411F9C523D28BBAAB32A5270E" "4DFA1F0F757EF8E0F30AF08FBDE1E7F4")) return FALSE; - // тест Б.4: сеанс протокола + // тест Б.4: сообщения if (!bakeTestMsgVal(4, _bpace_m1, _bpace_m2, _bpace_m3, _bpace_m4)) return FALSE; // тест bakeKDF (по данным из теста Б.4) diff --git a/test/crypto/bash_bench.c b/test/crypto/bash_bench.c index 0f01dd42..68dba38e 100644 --- a/test/crypto/bash_bench.c +++ b/test/crypto/bash_bench.c @@ -4,13 +4,14 @@ \brief Benchmarks for STB 34.101.77 (bash) \project bee2/test \created 2014.07.15 -\version 2025.05.12 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ #include +#include #include #include #include @@ -27,9 +28,9 @@ extern const char bash_platform[]; bool_t bashBench() { - octet belt_state[256]; - octet bash_state[1024]; - octet combo_state[256]; + mem_align_t belt_state[256 / sizeof(mem_align_t)]; + mem_align_t bash_state[1024 / sizeof(mem_align_t)]; + mem_align_t combo_state[64 / sizeof(mem_align_t)]; octet buf[1024]; octet hash[64]; size_t l, d; diff --git a/test/crypto/bash_test.c b/test/crypto/bash_test.c index 90f087c3..39492545 100644 --- a/test/crypto/bash_test.c +++ b/test/crypto/bash_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.77 (bash) \project bee2/test \created 2015.09.22 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -28,8 +28,8 @@ bool_t bashTest() { octet buf[192]; octet hash[64]; - octet state[1024]; - octet state1[1024]; + mem_align_t state[1024 / sizeof(mem_align_t)]; + mem_align_t state1[1024 / sizeof(mem_align_t)]; size_t pos; // подготовить память if (sizeof(state) < utilMax(3, diff --git a/test/crypto/bels_test.c b/test/crypto/bels_test.c index b2f0a287..66f738d2 100644 --- a/test/crypto/bels_test.c +++ b/test/crypto/bels_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.60 (bels) \project bee2/test \created 2013.06.27 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -35,8 +35,8 @@ bool_t belsTest() octet s[32]; octet si[33 * 5]; char id[] = "Alice"; - octet echo_state[64]; - octet combo_state[512]; + mem_align_t echo_state[64 / sizeof(mem_align_t)]; + mem_align_t combo_state[64 / sizeof(mem_align_t)]; // подготовить память if (sizeof(echo_state) < prngEcho_keep() || sizeof(combo_state) < prngCOMBO_keep()) diff --git a/test/crypto/belt_bench.c b/test/crypto/belt_bench.c index ab05e296..345ba27e 100644 --- a/test/crypto/belt_bench.c +++ b/test/crypto/belt_bench.c @@ -4,13 +4,14 @@ \brief Benchmarks for STB 34.101.31 (belt) \project bee2/test \created 2014.11.18 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ #include +#include #include #include #include @@ -25,8 +26,8 @@ bool_t beltBench() { const size_t reps = 5000; - octet belt_state[512]; - octet combo_state[256]; + mem_align_t belt_state[512 / sizeof(mem_align_t)]; + mem_align_t combo_state[64 / sizeof(mem_align_t)]; octet buf[1024]; octet key[32]; octet iv[16]; diff --git a/test/crypto/belt_test.c b/test/crypto/belt_test.c index e7e13c13..6c932e1e 100644 --- a/test/crypto/belt_test.c +++ b/test/crypto/belt_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.31 (belt) \project bee2/test \created 2012.06.20 -\version 2024.01.25 +\version 2025.10.02 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -131,7 +131,7 @@ bool_t beltTest() u32 key[8]; u32 block[4]; octet level[12]; - octet state[1024]; + mem_align_t state[1024 / sizeof(mem_align_t)]; size_t count; // подготовить память if (sizeof(state) < utilMax(17, @@ -154,7 +154,7 @@ bool_t beltTest() beltHMAC_keep())) return FALSE; // belt-H - beltHGen(state); + beltHGen((octet*)state); if (!memEq(state, beltH(), 256)) return FALSE; // belt-block: тест A.1-1 @@ -246,6 +246,9 @@ bool_t beltTest() return FALSE; } // belt-compr: тест A.8 + if (!memIsAligned(buf, 4) || !memIsAligned(hash, 4) || + !memIsAligned(hash1, 4)) + return FALSE; u32From((u32*)buf, beltH(), 32); u32From((u32*)hash, beltH() + 32, 32); memSetZero(hash1, 16); diff --git a/test/crypto/bign96_test.c b/test/crypto/bign96_test.c index a69d82f3..0ccd7e38 100644 --- a/test/crypto/bign96_test.c +++ b/test/crypto/bign96_test.c @@ -4,7 +4,7 @@ \brief Tests for bign96 signatures \project bee2/test \created 2021.01.20 -\version 2024.01.25 +\version 2025.10.01 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -26,10 +26,10 @@ brngCTRX: Расширение brngCTR */ typedef struct { - const octet* X; /*< дополнительное слово */ - size_t count; /*< размер X в октетах */ - size_t offset; /*< текущее смещение в X */ - octet state_ex[]; /*< состояние brngCTR */ + const octet* X; /*< дополнительное слово */ + size_t count; /*< размер X в октетах */ + size_t offset; /*< текущее смещение в X */ + mem_align_t state_ex[]; /*< состояние brngCTR */ } brng_ctrx_st; static size_t brngCTRX_keep() @@ -90,9 +90,9 @@ bool_t bign96Test() octet pubkey[48]; octet hash[32]; octet sig[34]; - octet brng_state[1024]; + mem_align_t state[1024 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(brng_state) < brngCTRX_keep()) + if (sizeof(state) < brngCTRX_keep()) return FALSE; // проверить параметры if (bign96ParamsStd(params, "1.2.112.0.2.0.34.101.45.3.0") != ERR_OK || @@ -104,11 +104,9 @@ bool_t bign96Test() != ERR_OK || oid_len != 11) return FALSE; // инициализировать ГПСЧ - brngCTRXStart(beltH() + 128, beltH() + 128 + 64, - beltH(), 8 * 32, brng_state); + brngCTRXStart(beltH() + 128, beltH() + 128 + 64, beltH(), 8 * 32, state); // управление ключами - if (bign96KeypairGen(privkey, pubkey, params, brngCTRXStepR, brng_state) != - ERR_OK) + if (bign96KeypairGen(privkey, pubkey, params, brngCTRXStepR, state) != ERR_OK) return FALSE; if (!hexEq(privkey, "B1E1CDDFCF5DD7BA278390F292EEB72B" @@ -132,8 +130,8 @@ bool_t bign96Test() // выработка и проверка подписи if (beltHash(hash, beltH(), 13) != ERR_OK) return FALSE; - if (bign96Sign(sig, params, oid_der, oid_len, hash, privkey, - brngCTRXStepR, brng_state) != ERR_OK) + if (bign96Sign(sig, params, oid_der, oid_len, hash, privkey, + brngCTRXStepR, state) != ERR_OK) return FALSE; if (!hexEq(sig, "4981BBDD8721C08FA347B89BD16FDDE6" diff --git a/test/crypto/bign_test.c b/test/crypto/bign_test.c index 1d9cf383..a896a998 100644 --- a/test/crypto/bign_test.c +++ b/test/crypto/bign_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.45 (bign) \project bee2/test \created 2012.08.27 -\version 2023.09.25 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -30,10 +30,10 @@ brngCTRX: Расширение brngCTR */ typedef struct { - const octet* X; /*< дополнительное слово */ - size_t count; /*< размер X в октетах */ - size_t offset; /*< текущее смещение в X */ - octet state_ex[]; /*< состояние brngCTR */ + const octet* X; /*< дополнительное слово */ + size_t count; /*< размер X в октетах */ + size_t offset; /*< текущее смещение в X */ + mem_align_t state_ex[]; /*< состояние brngCTR */ } brng_ctrx_st; static size_t brngCTRX_keep() @@ -124,8 +124,8 @@ bool_t bignTest() octet id_hash[64]; octet sig[64 + 32]; octet id_sig[64 + 32 + 128]; - octet brng_state[1024]; - octet zz_stack[512]; + mem_align_t state[1024 / sizeof(mem_align_t)]; + mem_align_t stack[512 / sizeof(mem_align_t)]; octet token[80]; word q[W_OF_O(32)]; word d[W_OF_O(32)]; @@ -137,8 +137,8 @@ bool_t bignTest() size_t iter = 10000; octet key[32]; // подготовить память - if (sizeof(brng_state) < brngCTRX_keep() || - sizeof(zz_stack) < zzMulMod_deep(W_OF_O(32))) + if (sizeof(state) < brngCTRX_keep() || + sizeof(stack) < zzMulMod_deep(W_OF_O(32))) return FALSE; // проверить таблицы Б.1, Б.2, Б.3 count = sizeof(der); @@ -176,11 +176,10 @@ bool_t bignTest() != ERR_OK || count != 11) return FALSE; // инициализировать ГПСЧ - brngCTRXStart(beltH() + 128, beltH() + 128 + 64, beltH(), 8 * 32, - brng_state); + brngCTRXStart(beltH() + 128, beltH() + 128 + 64, beltH(), 8 * 32, state); // тест Г.1 - if (bignKeypairGen(privkey, pubkey, params, brngCTRXStepR, brng_state) != - ERR_OK) + if (bignKeypairGen(privkey, pubkey, params, brngCTRXStepR, + state) != ERR_OK) return FALSE; if (!hexEq(privkey, "1F66B5B84B7339674533F0329C74F218" @@ -217,7 +216,7 @@ bool_t bignTest() if (beltHash(hash, beltH(), 13) != ERR_OK) return FALSE; if (bignSign(sig, params, der, count, hash, privkey, brngCTRXStepR, - brng_state) != ERR_OK) + state) != ERR_OK) return FALSE; if (!hexEq(sig, "E36B7F0377AE4C524027C387FADF1B20" @@ -249,7 +248,7 @@ bool_t bignTest() return FALSE; // тест Г.4 if (bignKeyWrap(token, params, beltH(), 18, beltH() + 32, pubkey, - brngCTRXStepR, brng_state) != ERR_OK) + brngCTRXStepR, state) != ERR_OK) return FALSE; if (!hexEq(token, "9B4EA669DABDF100A7D4B6E6EB76EE52" @@ -267,7 +266,7 @@ bool_t bignTest() if (beltHash(hash, beltH(), 48) != ERR_OK) return FALSE; if (bignSign(sig, params, der, count, hash, privkey, brngCTRXStepR, - brng_state) != ERR_OK) + state) != ERR_OK) return FALSE; if (!hexEq(sig, "47A63C8B9C936E94B5FAB3D9CBD78366" @@ -278,7 +277,7 @@ bool_t bignTest() return FALSE; // тест Г.5 bignKeyWrap(token, params, beltH(), 32, beltH() + 64, - pubkey, brngCTRXStepR, brng_state); + pubkey, brngCTRXStepR, state); if (!hexEq(token, "4856093A0F6C13015FC8E15F1B23A762" "02D2F4BA6E5EC52B78658477F6486DE6" @@ -303,7 +302,7 @@ bool_t bignTest() wwFrom(H, hash, 32); S0[W_OF_O(16)] = 1; wwSetZero(S0 + W_OF_O(16) + 1, W_OF_O(16) - 1); - zzMulMod(k, S0, d, q, W_OF_O(32), zz_stack); + zzMulMod(k, S0, d, q, W_OF_O(32), stack); zzAddMod(k, S1, k, q, W_OF_O(32)); zzAddMod(k, k, H, q, W_OF_O(32)); wwTo(k, 32, k); @@ -324,7 +323,7 @@ bool_t bignTest() wwFrom(H, hash, 32); S0[W_OF_O(16)] = 1; wwSetZero(S0 + W_OF_O(16) + 1, W_OF_O(16) - 1); - zzMulMod(k, S0, d, q, W_OF_O(32), zz_stack); + zzMulMod(k, S0, d, q, W_OF_O(32), stack); zzAddMod(k, S1, k, q, W_OF_O(32)); zzAddMod(k, k, H, q, W_OF_O(32)); wwTo(k, 32, k); @@ -336,7 +335,7 @@ bool_t bignTest() if (beltHash(hash, beltH() + 32, 16) != ERR_OK) return FALSE; if (bignIdSign(id_sig, params, der, count, id_hash, hash, id_privkey, - brngCTRXStepR, brng_state) != ERR_OK) + brngCTRXStepR, state) != ERR_OK) return FALSE; if (!hexEq(id_sig, "1697FE6A073D3B28C9D0DD832A169D7B" @@ -359,7 +358,7 @@ bool_t bignTest() if (beltHash(hash, beltH() + 32, 23) != ERR_OK) return FALSE; if (bignIdSign(id_sig, params, der, count, id_hash, hash, id_privkey, - brngCTRXStepR, brng_state) != ERR_OK) + brngCTRXStepR, state) != ERR_OK) return FALSE; if (!hexEq(id_sig, "31CBA14FC2D79AFCD8F50E29F993FC2C" @@ -408,9 +407,9 @@ bool_t bignTest() return FALSE; // дополнительный тест: транспорт ключа из 16 октетов if (bignKeyWrap(token, params, beltH(), 16, beltH() + 64, - pubkey, brngCTRXStepR, brng_state) != ERR_OK || + pubkey, brngCTRXStepR, state) != ERR_OK || bignKeyUnwrap(token, params, token, 32 + 16 + 16, beltH() + 64, - privkey) != ERR_OK || + privkey) != ERR_OK || !memEq(token, beltH(), 16)) return FALSE; // дополнительные тесты (vs OpenSSL) diff --git a/test/crypto/botp_test.c b/test/crypto/botp_test.c index 8e798a4f..3dafb715 100644 --- a/test/crypto/botp_test.c +++ b/test/crypto/botp_test.c @@ -35,7 +35,7 @@ bool_t botpTest() char p_str[72]; char s_str[136]; tm_time_t t; - octet state[2048]; + mem_align_t state[2048 / sizeof(mem_align_t)]; // подготовить память if (sizeof(state) < utilMax(3, botpHOTP_keep(), diff --git a/test/crypto/brng_test.c b/test/crypto/brng_test.c index d5f3daa8..1fa2f540 100644 --- a/test/crypto/brng_test.c +++ b/test/crypto/brng_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.47 (brng) \project bee2/test \created 2013.04.01 -\version 2025.04.25 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -35,7 +35,7 @@ bool_t brngTest() octet buf1[256]; octet iv[128]; octet iv1[32]; - octet state[1024]; + mem_align_t state[1024 / sizeof(mem_align_t)]; // подготовить память if (sizeof(state) < brngCTR_keep() || sizeof(state) < brngHMAC_keep()) diff --git a/test/crypto/btok_test.c b/test/crypto/btok_test.c index 2166c615..6806d142 100644 --- a/test/crypto/btok_test.c +++ b/test/crypto/btok_test.c @@ -4,7 +4,7 @@ \brief Tests for STB 34.101.79 (btok) \project bee2/test \created 2022.07.07 -\version 2025.01.08 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -104,7 +104,7 @@ CV-сертификаты static bool_t btokCVCTest() { - octet echo[256]; + mem_align_t state[64 / sizeof(mem_align_t)]; btok_cvc_t cvc0[1]; btok_cvc_t cvc1[1]; btok_cvc_t cvc2[1]; @@ -123,7 +123,7 @@ static bool_t btokCVCTest() octet cert3[400]; size_t cert3_len, cert3_len1; // запустить ГПСЧ - prngEchoStart(echo, beltH(), 256); + prngEchoStart(state, beltH(), 256); // определить максимальную длину сертификата memSetZero(cvc0, sizeof(btok_cvc_t)); strCopy(cvc0->authority, "BYCA00000000"); @@ -137,7 +137,7 @@ static bool_t btokCVCTest() return FALSE; if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.3") != ERR_OK || bignKeypairGen(privkey0, cvc0->pubkey, params, prngEchoStepR, - echo) != ERR_OK || + state) != ERR_OK || btokCVCCheck(cvc0) != ERR_OK) return FALSE; if (btokCVCWrap(0, 0, cvc0, privkey0, 64) != ERR_OK) @@ -177,7 +177,7 @@ static bool_t btokCVCTest() cvc1->pubkey_len = 96; if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.2") != ERR_OK || bignKeypairGen(privkey1, cvc1->pubkey, params, prngEchoStepR, - echo) != ERR_OK || + state) != ERR_OK || btokCVCCheck(cvc1) != ERR_OK) return FALSE; // создать pre-cert1 (запрос на выпуск сертификата) @@ -214,7 +214,7 @@ static bool_t btokCVCTest() cvc2->pubkey_len = 64; if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1") != ERR_OK || bignKeypairGen(privkey2, cvc2->pubkey, params, prngEchoStepR, - echo) != ERR_OK || + state) != ERR_OK || btokCVCCheck(cvc2) != ERR_OK) return FALSE; // выпустить cert2 @@ -238,7 +238,7 @@ static bool_t btokCVCTest() cvc3->pubkey_len = 48; if (bign96ParamsStd(params, "1.2.112.0.2.0.34.101.45.3.0") != ERR_OK || bign96KeypairGen(privkey3, cvc3->pubkey, params, prngEchoStepR, - echo) != ERR_OK || + state) != ERR_OK || btokCVCCheck(cvc3) != ERR_OK) return FALSE; // выпустить cert3 @@ -269,22 +269,32 @@ SM ******************************************************************************* */ +#define btokSMTest_local()\ +/* state_t */ btokSM_keep(),\ +/* state_ct */ btokSM_keep(),\ +/* cmd */ sizeof(apdu_cmd_t) + 257,\ +/* cmd1 */ sizeof(apdu_cmd_t) + 257,\ +/* resp */ sizeof(apdu_resp_t) + 257,\ +/* resp1 */ sizeof(apdu_resp_t) + 257 + static bool_t btokSMTest() { - octet state_t[512]; - octet state_ct[512]; - octet stack[4096]; - apdu_cmd_t* cmd = (apdu_cmd_t*)stack; - apdu_cmd_t* cmd1 = (apdu_cmd_t*)(stack + 1024); - apdu_resp_t* resp = (apdu_resp_t*)(stack + 2 * 1024); - apdu_resp_t* resp1 = (apdu_resp_t*)(stack + 3 * 1024); + mem_align_t state[4096 / sizeof(mem_align_t)]; + octet* state_t; /* [btokSM_keep()] */ + octet* state_ct; /* [btokSM_keep()] */ + apdu_cmd_t* cmd; /* sizeof(apdu_cmd_t) + 257 */ + apdu_cmd_t* cmd1; /* sizeof(apdu_cmd_t) + 257 */ + apdu_resp_t* resp; /* sizeof(apdu_resp_t) + 257 */ + apdu_resp_t* resp1; /* sizeof(apdu_resp_t) + 257 */ octet apdu[1024]; size_t count, count1; size_t size, size1; - // подготовить состояния - if (sizeof(state_t) < btokSM_keep() || - sizeof(state_ct) < btokSM_keep()) + // разметить состояние + if (sizeof(state) < memSliceSize(btokSMTest_local(), SIZE_MAX)) return FALSE; + memSlice(state, + btokSMTest_local(), SIZE_MAX, + &state_t, &state_ct, &cmd, &cmd1, &resp, &resp1); // запустить SM btokSMStart(state_t, beltH()); btokSMStart(state_ct, beltH()); @@ -378,7 +388,7 @@ static bool_t btokSMTest() return FALSE; btokSMCtrInc(state_ct); if (btokSMCmdUnwrap(0, &size, apdu, count, state_ct) != ERR_OK || - size > sizeof(stack) / 4 || + size > sizeof(apdu_cmd_t) + 257 || btokSMCmdUnwrap(cmd1, &size1, apdu, count, state_ct) != ERR_OK || size1 != size || !memEq(cmd, cmd1, size)) @@ -392,7 +402,7 @@ static bool_t btokSMTest() return FALSE; btokSMCtrInc(state_t); if (btokSMRespUnwrap(0, &size, apdu, count, state_t) != ERR_OK || - size > sizeof(stack) / 4 || + size > sizeof(apdu_resp_t) + 257 || btokSMRespUnwrap(resp1, &size1, apdu, count, state_t) != ERR_OK || size1 != size || !memEq(resp, resp1, size)) @@ -450,8 +460,6 @@ static err_t bakeTestCertVal(octet* pubkey, const bign_params* params, static bool_t btokBAUTHTest() { bign_params params[1]; - octet echoa[64]; - octet echob[64]; bake_settings settingsa[1]; bake_settings settingsb[1]; octet da[32]; @@ -462,16 +470,19 @@ static bool_t btokBAUTHTest() bake_cert certb[1]; octet keya[32]; octet keyb[32]; - octet statea[20000]; - octet stateb[20000]; + mem_align_t echo_statea[64 / sizeof(mem_align_t)]; + mem_align_t echo_stateb[64 / sizeof(mem_align_t)]; + mem_align_t bauth_statea[16384 / sizeof(mem_align_t)]; + mem_align_t bauth_stateb[16384 / sizeof(mem_align_t)]; octet buf[1000]; // загрузить долговременные параметры if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1") != ERR_OK) return FALSE; // подготовить память - if (sizeof(echoa) < prngEcho_keep() || - sizeof(statea) < btokBAuthT_keep(128) || - sizeof(stateb) < btokBAuthCT_keep(128)) + if (sizeof(echo_statea) < prngEcho_keep() || + sizeof(echo_stateb) < prngEcho_keep() || + sizeof(bauth_statea) < btokBAuthT_keep(128) || + sizeof(bauth_stateb) < btokBAuthCT_keep(128)) return FALSE; // загрузить личные ключи hexTo(da, _da); @@ -485,8 +496,8 @@ static bool_t btokBAUTHTest() certb->len = strLen(_certb) / 2; certa->val = certb->val = bakeTestCertVal; // очистка - memSetZero(statea, sizeof(statea)); - memSetZero(stateb, sizeof(stateb)); + memSetZero(bauth_statea, sizeof(bauth_statea)); + memSetZero(bauth_stateb, sizeof(bauth_stateb)); memSetZero(keya, sizeof(keya)); memSetZero(keyb, sizeof(keyb)); memSetZero(buf, sizeof(buf)); @@ -496,29 +507,31 @@ static bool_t btokBAUTHTest() settingsa->kca = settingsb->kca = TRUE; settingsa->kcb = settingsb->kcb = TRUE; settingsa->rng = settingsb->rng = prngEchoStepR; - settingsa->rng_state = echoa; - settingsb->rng_state = echob; - prngEchoStart(echoa, beltH(), 128); - prngEchoStart(echob, beltH() + 128, 128); + settingsa->rng_state = echo_statea; + settingsb->rng_state = echo_stateb; + prngEchoStart(echo_statea, beltH(), 128); + prngEchoStart(echo_stateb, beltH() + 128, 128); // инициализация - if (btokBAuthTStart(statea, params, settingsa, da, certa) != ERR_OK || - btokBAuthCTStart(stateb, params, settingsb, db, certb) != ERR_OK) + if (btokBAuthTStart(bauth_statea, params, settingsa, da, + certa) != ERR_OK || + btokBAuthCTStart(bauth_stateb, params, settingsb, db, + certb) != ERR_OK) return FALSE; // шаги протокола, с аутентификацией КТ - if (btokBAuthCTStep2(buf, certa, stateb) != ERR_OK || - btokBAuthTStep3(buf, buf, statea) != ERR_OK || - btokBAuthCTStep4(buf, buf, stateb) != ERR_OK || + if (btokBAuthCTStep2(buf, certa, bauth_stateb) != ERR_OK || + btokBAuthTStep3(buf, buf, bauth_statea) != ERR_OK || + btokBAuthCTStep4(buf, buf, bauth_stateb) != ERR_OK || btokBAuthTStep5(buf, 8 + 32 + certb->len, - bakeTestCertVal, statea) != ERR_OK) + bakeTestCertVal, bauth_statea) != ERR_OK) return FALSE; // извлечение ключей - if (btokBAuthCTStepG(keyb, stateb) != ERR_OK || - btokBAuthTStepG(keya, statea) != ERR_OK || + if (btokBAuthCTStepG(keyb, bauth_stateb) != ERR_OK || + btokBAuthTStepG(keya, bauth_statea) != ERR_OK || !memEq(keya, keyb, 32)) return FALSE; // очистка - memSetZero(statea, sizeof(statea)); - memSetZero(stateb, sizeof(stateb)); + memSetZero(bauth_statea, sizeof(bauth_statea)); + memSetZero(bauth_stateb, sizeof(bauth_stateb)); memSetZero(keya, sizeof(keya)); memSetZero(keyb, sizeof(keyb)); memSetZero(buf, sizeof(buf)); @@ -528,22 +541,24 @@ static bool_t btokBAUTHTest() settingsa->kca = settingsb->kca = TRUE; settingsa->kcb = settingsb->kcb = FALSE; settingsa->rng = settingsb->rng = prngEchoStepR; - settingsa->rng_state = echoa; - settingsb->rng_state = echob; - prngEchoStart(echoa, beltH(), 128); - prngEchoStart(echob, beltH() + 128, 128); + settingsa->rng_state = echo_statea; + settingsb->rng_state = echo_stateb; + prngEchoStart(echo_statea, beltH(), 128); + prngEchoStart(echo_stateb, beltH() + 128, 128); // инициализация - if (btokBAuthTStart(statea, params, settingsa, da, certa) != ERR_OK || - btokBAuthCTStart(stateb, params, settingsb, db, certb) != ERR_OK) + if (btokBAuthTStart(bauth_statea, params, settingsa, da, + certa) != ERR_OK || + btokBAuthCTStart(bauth_stateb, params, settingsb, db, + certb) != ERR_OK) return FALSE; // шаги протокола, без аутентификациии КТ - if (btokBAuthCTStep2(buf, certa, stateb) != ERR_OK || - btokBAuthTStep3(buf, buf, statea) != ERR_OK || - btokBAuthCTStep4(buf, buf, stateb) != ERR_OK) + if (btokBAuthCTStep2(buf, certa, bauth_stateb) != ERR_OK || + btokBAuthTStep3(buf, buf, bauth_statea) != ERR_OK || + btokBAuthCTStep4(buf, buf, bauth_stateb) != ERR_OK) return FALSE; // извлечение ключей - if (btokBAuthCTStepG(keyb, stateb) != ERR_OK || - btokBAuthTStepG(keya, statea) != ERR_OK || + if (btokBAuthCTStepG(keyb, bauth_stateb) != ERR_OK || + btokBAuthTStepG(keya, bauth_statea) != ERR_OK || !memEq(keya, keyb, 32)) return FALSE; // все нормально diff --git a/test/crypto/dstu_test.c b/test/crypto/dstu_test.c index 0c365084..ab38d2a9 100644 --- a/test/crypto/dstu_test.c +++ b/test/crypto/dstu_test.c @@ -4,7 +4,7 @@ \brief Tests for DSTU 4145-2002 (Ukraine) \project bee2/test \created 2012.03.01 -\version 2024.02.29 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -45,7 +45,7 @@ bool_t dstuTest() octet hash[32]; octet sig[2 * DSTU_SIZE]; size_t ld; - octet state[512]; + mem_align_t state[512 / sizeof(mem_align_t)]; // подготовить память if (sizeof(state) < prngEcho_keep() || sizeof(state) < prngCOMBO_keep()) diff --git a/test/crypto/g12s_test.c b/test/crypto/g12s_test.c index 7e649d3a..87d2a88e 100644 --- a/test/crypto/g12s_test.c +++ b/test/crypto/g12s_test.c @@ -4,13 +4,14 @@ \brief Tests for GOST R 34.10-2012 (Russia) \project bee2/test \created 2014.04.07 -\version 2025.05.07 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ #include +#include #include #include @@ -31,10 +32,10 @@ bool_t g12sTest() octet pubkey[2 * G12S_FIELD_SIZE]; octet hash[64]; octet sig[2 * G12S_ORDER_SIZE]; - octet echo[64]; + mem_align_t state[64 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(echo) < prngEcho_keep() || - sizeof(echo) < prngCOMBO_keep()) + if (sizeof(state) < prngEcho_keep() || + sizeof(state) < prngCOMBO_keep()) return FALSE; // тест A.1 [загрузка параметров] if (g12sParamsStd(params, "1.2.643.2.2.35.0") != ERR_OK || @@ -44,8 +45,8 @@ bool_t g12sTest() hexToRev(buf, "7A929ADE789BB9BE10ED359DD39A72C1" "1B60961F49397EEE1D19CE9891EC3B28"); - prngEchoStart(echo, buf, 32); - if (g12sKeypairGen(privkey, pubkey, params, prngEchoStepR, echo) + prngEchoStart(state, buf, 32); + if (g12sKeypairGen(privkey, pubkey, params, prngEchoStepR, state) != ERR_OK || !hexEqRev(privkey, "7A929ADE789BB9BE10ED359DD39A72C1" @@ -63,7 +64,7 @@ bool_t g12sTest() hexToRev(buf, "77105C9B20BCD3122823C8CF6FCC7B95" "6DE33814E95B7FE64FED924594DCEAB3"); - if (g12sSign(sig, params, hash, privkey, prngEchoStepR, echo) != ERR_OK || + if (g12sSign(sig, params, hash, privkey, prngEchoStepR, state) != ERR_OK || !hexEq(sig, "41AA28D2F1AB148280CD9ED56FEDA419" "74053554A42767B83AD043FD39DC0493" @@ -84,9 +85,9 @@ bool_t g12sTest() "3091A0E8514669700EE7508E508B1020" "72E8123B2200A0563322DAD2827E2714" "A2636B7BFD18AADFC62967821FA18DD4"); - prngEchoStart(echo, buf, 64); - if (g12sKeypairGen(privkey, pubkey, params, prngEchoStepR, echo) - != ERR_OK || + prngEchoStart(state, buf, 64); + if (g12sKeypairGen(privkey, pubkey, params, prngEchoStepR, + state) != ERR_OK || !hexEqRev(privkey, "0BA6048AADAE241BA40936D47756D7C9" "3091A0E8514669700EE7508E508B1020" @@ -113,8 +114,8 @@ bool_t g12sTest() "946312120B39D019D455986E364F3658" "86748ED7A44B3E794434006011842286" "212273A6D14CF70EA3AF71BB1AE679F1"); - if (g12sSign(sig, params, hash, privkey, prngEchoStepR, echo) - != ERR_OK || + if (g12sSign(sig, params, hash, privkey, prngEchoStepR, + state) != ERR_OK || !hexEq(sig, "2F86FA60A081091A23DD795E1E3C689E" "E512A3C82EE0DCC2643C78EEA8FCACD3" diff --git a/test/crypto/pfok_test.c b/test/crypto/pfok_test.c index b87ba0cf..f46b32eb 100644 --- a/test/crypto/pfok_test.c +++ b/test/crypto/pfok_test.c @@ -4,7 +4,7 @@ \brief Tests for Draft of RD_RB (pfok) \project bee2/test \created 2014.07.08 -\version 2025.05.07 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -120,14 +120,14 @@ bool_t pfokTest() { pfok_params params[1]; pfok_seed seed[1]; - octet combo_state[128]; + mem_align_t state[64 / sizeof(mem_align_t)]; octet ua[O_OF_B(130)]; octet xa[O_OF_B(130)]; octet vb[O_OF_B(638)]; octet yb[O_OF_B(638)]; octet key[32]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep()) + if (sizeof(state) < prngCOMBO_keep()) return FALSE; // тест PFOK.GENP.1 if (!pfokTestParamsTest()) @@ -160,8 +160,8 @@ bool_t pfokTest() if (pfokParamsStd(params, seed, "test") != ERR_OK) return FALSE; // сгенерировать ключи - prngCOMBOStart(combo_state, utilNonce32()); - if (pfokKeypairGen(ua, vb, params, prngCOMBOStepR, combo_state) != ERR_OK || + prngCOMBOStart(state, utilNonce32()); + if (pfokKeypairGen(ua, vb, params, prngCOMBOStepR, state) != ERR_OK || pfokPubkeyVal(params, vb) != ERR_OK || pfokPubkeyCalc(yb, params, ua) != ERR_OK || !memEq(vb, yb, O_OF_B(params->l))) diff --git a/test/math/ecp_bench.c b/test/math/ecp_bench.c index 1b73a60d..b5a1f47b 100644 --- a/test/math/ecp_bench.c +++ b/test/math/ecp_bench.c @@ -4,13 +4,14 @@ \brief Benchmarks for elliptic curves over prime fields \project bee2/test \created 2013.10.17 -\version 2025.04.25 +\version 2025.09.30 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ #include +#include #include #include #include @@ -23,38 +24,34 @@ ******************************************************************************* */ -static size_t _ecpBench_deep(size_t n, size_t f_deep, size_t ec_d, - size_t ec_deep) -{ - return O_OF_W(3 * n) + prngCOMBO_keep() + - ecMulA_deep(n, ec_d, ec_deep, n); -} - bool_t ecpBench() { - // описание кривой bign_params params[1]; - // состояние - octet state[6000]; ec_o* ec; - octet* combo_state; - word* pt; - word* d; + void* state; + octet* combo_state; /* [prngCOMBO_keep()] */ + word* pt; /* [2 * n] */ + word* d; /* [n] */ void* stack; - // подготовить память - if (sizeof(state) < bignStart_keep(128, _ecpBench_deep)) - return FALSE; - // загрузить параметры и создать описание кривой + // загрузить параметры if (bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1") != ERR_OK || - bignStart(state, params) != ERR_OK) + bignEcCreate(&ec, params) != ERR_OK) return FALSE; - // раскладка состояния - ec = (ec_o*)state; + // заблокировать утроение точек ec->tpl = 0; - combo_state = objEnd(ec, octet); - pt = (word*)(combo_state + prngCOMBO_keep()); - d = pt + 2 * ec->f->n; - stack = d + ec->f->n; + // создать состояние + state = blobCreate2( + prngCOMBO_keep(), + O_OF_W(2 * ec->f->n), + O_OF_W(ec->f->n), + ecMulA_deep(ec->f->n, ec->d, ec->deep, ec->f->n), + SIZE_MAX, + &combo_state, &pt, &d, &stack); + if (state == 0) + { + bignEcClose(ec); + return FALSE; + } // создать генератор COMBO prngCOMBOStart(combo_state, utilNonce32()); // оценить число кратных точек в секунду @@ -70,10 +67,12 @@ bool_t ecpBench() } ticks = tmTicks() - ticks; // печать результатов - printf("ecpBench: %u cycles/mulpoint [%u mulpoints/sec]\n", + printf("ecpBench: %u cycles/mulpoint [%u mulpoints/sec]\n", (unsigned)(ticks / reps), (unsigned)tmSpeed(reps, ticks)); } - // все нормально + // завершение + blobClose(state); + bignEcClose(ec); return TRUE; } diff --git a/test/math/ecp_test.c b/test/math/ecp_test.c index 586b27d4..67ec0bce 100644 --- a/test/math/ecp_test.c +++ b/test/math/ecp_test.c @@ -4,12 +4,13 @@ \brief Tests for elliptic curves over prime fields \project bee2/test \created 2017.05.29 -\version 2023.03.30 +\version 2025.09.15 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* */ +#include #include #include #include @@ -50,147 +51,141 @@ bool_t ecpTest() // размерности const size_t n = W_OF_O(no); const size_t f_keep = gfpCreate_keep(no); - const size_t ec_keep = ecpCreateJ_keep(n); const size_t f_deep = gfpCreate_deep(no); - // состояние и стек - octet state[2048]; - octet stack[2048]; - octet t[32 * 5]; - // поле и эк - qr_o* f; - ec_o* ec; - // подготовить память - if (sizeof(state) < f_keep + ec_keep || - sizeof(stack) < f_deep || - sizeof(t) < 3 * no) + const size_t ec_keep = ecpCreateJ_keep(n); + const size_t ec_deep = ecpCreateJ_deep(n, f_deep); + // состояние + void* state; + ec_o* ec; /* [ec_keep] */ + qr_o* f; /* [f_keep] */ + octet* t; /* [5 * no] */ + void* stack; + // создать состояние + state = blobCreate2( + ec_keep, + f_keep, + 5 * no, + utilMax(12, + gfpCreate_deep(no), + ecpCreateJ_deep(n, f_deep), + ecGroupCreate_deep(f_deep), + ecpIsValid_deep(n, f_deep), + ecpGroupSeemsValid_deep(n, f_deep), + ecpGroupIsSafe_deep(n), + ecHasOrderA_deep(n, 3, ec_deep, n), + ec_deep, + ecpIsOnA_deep(n, f_deep), + ecpAddAA_deep(n, f_deep), + ecpSubAA_deep(n, f_deep), + ecMulA_deep(n, 3, ec_deep, 1)), + SIZE_MAX, + &ec, &f, &t, &stack); + if (state == 0) return FALSE; // создать f = GF(p) hexToRev(t, p); - f = (qr_o*)(state + ec_keep); if (!gfpCreate(f, t, no, stack)) return FALSE; // создать ec = EC_{ab}(f) hexToRev(t, a), hexToRev(t + no, b); - ec = (ec_o*)state; - if (sizeof(stack) < ecpCreateJ_deep(n, f_deep) || - !ecpCreateJ(ec, f, t, t + no, stack)) + if (!ecpCreateJ(ec, f, t, t + no, stack) || ec->d != 3) + { + blobClose(state); return FALSE; + } // создать группу точек ec hexToRev(t, xbase), hexToRev(t + no, ybase), hexToRev(t + 2 * no, q); - if (sizeof(stack) < ecCreateGroup_deep(f_deep) || - !ecCreateGroup(ec, t, t + no, t + 2 * no, no, cofactor, stack)) + if (!ecGroupCreate(ec, t, t + no, t + 2 * no, no, cofactor, stack)) + { + blobClose(state); return FALSE; + } // присоединить f к ec objAppend(ec, f, 0); // корректная кривая? - if (sizeof(stack) < ecpIsValid_deep(n, f_deep) || - !ecpIsValid(ec, stack)) - return FALSE; // корректная группа? - if (sizeof(stack) < ecpSeemsValidGroup_deep(n, f_deep) || - !ecpSeemsValidGroup(ec, stack)) - return FALSE; // надежная группа? - if (sizeof(stack) < ecpIsSafeGroup_deep(n) || - !ecpIsSafeGroup(ec, 40, stack)) - return FALSE; - // базовая точка имеет порядок q? - if (sizeof(stack) < ecHasOrderA_deep(n, ec->d, ec->deep, n) || + // базовая точнка имеет порядок q? + if (!ecpIsValid(ec, stack) || + !ecpGroupSeemsValid(ec, stack) || + !ecpGroupIsSafe(ec, 40, stack) || !ecHasOrderA(ec->base, ec, ec->order, n, stack)) + { + blobClose(state); return FALSE; + } // утроить базовую точку разными способами - if (sizeof(t) < (2 + ec->d) * no || - sizeof(stack) < utilMax(5, - ec->deep, - ecpIsOnA_deep(n, f_deep), - ecpAddAA_deep(n, f_deep), - ecpSubAA_deep(n, f_deep), - ecMulA_deep(n, ec->d, ec->deep, 1))) - return FALSE; { word* pts = (word*)t; word d = 3; // удвоить и сложить if (!ecpIsOnA(ec->base, ec, stack) || !ecpAddAA(pts, ec->base, ec->base, ec, stack) || - !ecpAddAA(pts, pts, ec->base, ec, stack)) - return FALSE; + !ecpAddAA(pts, pts, ec->base, ec, stack) || // дважды удвоить и вычесть - if (!ecpAddAA(pts + 2 * n, ec->base, ec->base, ec, stack) || + !ecpAddAA(pts + 2 * n, ec->base, ec->base, ec, stack) || !ecpAddAA(pts + 2 * n, pts + 2 * n, pts + 2 * n, ec, stack) || !ecpSubAA(pts + 2 * n, pts + 2 * n, ec->base, ec, stack) || - !memEq(pts, pts + 2 * n, 2 * n)) - return FALSE; - ecpNegA(pts + 2 * n, pts + 2 * n, ec); - if (ecpAddAA(pts + 2 * n, pts, pts + 2 * n, ec, stack)) - return FALSE; + !memEq(pts, pts + 2 * n, 2 * n) || + (ecpNegA(pts + 2 * n, pts + 2 * n, ec), + ecpAddAA(pts + 2 * n, pts, pts + 2 * n, ec, stack)) || // вычислить кратную точку - if (!ecMulA(pts + 2 * n, ec->base, ec, &d, 1, stack) || - !memEq(pts, pts + 2 * n, 2 * n)) - return FALSE; + !ecMulA(pts + 2 * n, ec->base, ec, &d, 1, stack) || + !memEq(pts, pts + 2 * n, 2 * n) || // утроить напрямую - if (!ec->froma || !ec->tpl || !ec->toa) - return FALSE; - ec->froma(pts + 2 * n, ec->base, ec, stack); - ec->tpl(pts + 2 * n, pts + 2 * n, ec, stack); - ec->toa(pts + 2 * n, pts + 2 * n, ec, stack); - if (!memEq(pts, pts + 2 * n, 2 * n)) + !ec->froma || !ec->tpl || !ec->toa || + (ec->froma(pts + 2 * n, ec->base, ec, stack), + ec->tpl(pts + 2 * n, pts + 2 * n, ec, stack), + ec->toa(pts + 2 * n, pts + 2 * n, ec, stack), + !memEq(pts, pts + 2 * n, 2 * n))) + { + blobClose(state); return FALSE; + } } // вывести f = GF(p) за пределы ec - f = (qr_o*)(state + ec_keep); - memMove(f, objPtr(ec, 0, qr_o), f_keep); + objCopy(f, objPtr(ec, 0, qr_o)); // создать ec = EC_{a-1, b}(f) hexToRev(t, a), --t[0], hexToRev(t + no, b); - ec = (ec_o*)state; - if (sizeof(stack) < ecpCreateJ_deep(n, f_deep) || - !ecpCreateJ(ec, f, t, t + no, stack)) + if (!ecpCreateJ(ec, f, t, t + no, stack)) + { + blobClose(state); return FALSE; - // присоединить f к ec + } + // заново присоединить f к ec objAppend(ec, f, 0); // точка (xbase = 0, ybase) все еще лежит на ec: ybase^2 = b hexToRev(t, xbase), hexToRev(t + no, ybase); wwFrom(ec->base, t, no), wwFrom(ec->base + n, t + no, no); ASSERT(wwIsZero(ec->base, n)); // утроить базовую точку разными способами - if (sizeof(t) < (2 + ec->d) * no || - sizeof(stack) < utilMax(5, - ec->deep, - ecpIsOnA_deep(n, f_deep), - ecpAddAA_deep(n, f_deep), - ecpSubAA_deep(n, f_deep), - ecMulA_deep(n, ec->d, ec->deep, 1))) - return FALSE; { word* pts = (word*)t; word d = 3; // удвоить и сложить if (!ecpIsOnA(ec->base, ec, stack) || !ecpAddAA(pts, ec->base, ec->base, ec, stack) || - !ecpAddAA(pts, pts, ec->base, ec, stack)) - return FALSE; + !ecpAddAA(pts, pts, ec->base, ec, stack) || // дважды удвоить и вычесть - if (!ecpAddAA(pts + 2 * n, ec->base, ec->base, ec, stack) || + !ecpAddAA(pts + 2 * n, ec->base, ec->base, ec, stack) || !ecpAddAA(pts + 2 * n, pts + 2 * n, pts + 2 * n, ec, stack) || !ecpSubAA(pts + 2 * n, pts + 2 * n, ec->base, ec, stack) || - !memEq(pts, pts + 2 * n, 2 * n)) - return FALSE; - ecpNegA(pts + 2 * n, pts + 2 * n, ec); - if (ecpAddAA(pts + 2 * n, pts, pts + 2 * n, ec, stack)) - return FALSE; + !memEq(pts, pts + 2 * n, 2 * n) || + (ecpNegA(pts + 2 * n, pts + 2 * n, ec), + ecpAddAA(pts + 2 * n, pts, pts + 2 * n, ec, stack)) || // вычислить кратную точку - if (!ecMulA(pts + 2 * n, ec->base, ec, &d, 1, stack) || - !memEq(pts, pts + 2 * n, 2 * n)) - return FALSE; - // утроить напрямую - if (!ec->froma || !ec->tpl || !ec->toa) - return FALSE; - ec->froma(pts + 2 * n, ec->base, ec, stack); - ec->tpl(pts + 2 * n, pts + 2 * n, ec, stack); - ec->toa(pts + 2 * n, pts + 2 * n, ec, stack); - if (!memEq(pts, pts + 2 * n, 2 * n)) + !ecMulA(pts + 2 * n, ec->base, ec, &d, 1, stack) || + !memEq(pts, pts + 2 * n, 2 * n) || + (ec->froma(pts + 2 * n, ec->base, ec, stack), + ec->tpl(pts + 2 * n, pts + 2 * n, ec, stack), + ec->toa(pts + 2 * n, pts + 2 * n, ec, stack), + !memEq(pts, pts + 2 * n, 2 * n))) + { + blobClose(state); return FALSE; + } } - // все нормально + // все хорошо + blobClose(state); return TRUE; } diff --git a/test/math/pp_test.c b/test/math/pp_test.c index 7fc940e3..e6870b18 100644 --- a/test/math/pp_test.c +++ b/test/math/pp_test.c @@ -4,7 +4,7 @@ \brief Tests for the arithmetic of binary polynomials \project bee2/test \created 2023.11.09 -\version 2023.11.10 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -78,10 +78,10 @@ static bool_t ppTestExps16() word t[n]; u16 s1[65536]; u16 s2[65536]; - octet stack[1024]; + mem_align_t stack[1024 / sizeof(mem_align_t)]; size_t pos; // подготовить память - if (sizeof(stack) < utilMax(2, + if (sizeof(stack) < utilMax(2, ppIsIrred_deep(n), ppMulMod_deep(n))) return FALSE; @@ -140,21 +140,20 @@ static bool_t ppTestRed() word t[2 * n]; word t1[2 * n]; word mod[n]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || - sizeof(stack) < utilMax(1, - ppRed_deep(n))) + if (sizeof(state) < prngCOMBO_keep() || + sizeof(stack) < ppRed_deep(n)) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // редукция while (reps--) { size_t m; // генерация - prngCOMBOStepR(a, 2 * O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(2 * n), state); // ppRed / ppRedTrinomial[kb233] ASSERT(W_OF_B(233) == W_OF_B(234)); m = W_OF_B(233); @@ -223,6 +222,5 @@ static bool_t ppTestRed() bool_t ppTest() { - return ppTestExps16() && - ppTestRed(); + return ppTestExps16() && ppTestRed(); } diff --git a/test/math/pri_test.c b/test/math/pri_test.c index 1fba64cc..db3c0ecc 100644 --- a/test/math/pri_test.c +++ b/test/math/pri_test.c @@ -4,7 +4,7 @@ \brief Tests for prime numbers \project bee2/test \created 2014.07.07 -\version 2025.04.25 +\version 2025.09.29 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -31,15 +31,16 @@ bool_t priTest() word a[W_OF_B(521)]; word p[W_OF_B(289)]; word mods[1024]; - octet combo_state[32]; - octet stack[4096]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[4096 / sizeof(mem_align_t)]; // инициализировать генератор COMBO - if (sizeof(combo_state) < prngCOMBO_keep()) + if (sizeof(state) < prngCOMBO_keep()) return FALSE; - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // проверить простоту элементов факторной базы - if (sizeof(stack) < priIsPrimeW_deep() || - sizeof(stack) < priIsPrime_deep(1)) + if (sizeof(stack) < utilMax(2, + priIsPrimeW_deep(), + priIsPrime_deep(1))) return FALSE; for (i = 0; i < priBaseSize(); ++i) { @@ -61,8 +62,9 @@ bool_t priTest() a[n++] = w; } // проверить гладкость и просеянность - if (sizeof(stack) < priIsSieved_deep(n) || - sizeof(stack) < priIsSmooth_deep(n) || + if (sizeof(stack) < utilMax(2, + priIsSieved_deep(n), + priIsSmooth_deep(n)) || priIsSieved(a, n, i, stack) || !priIsSmooth(a, n, i, stack)) return FALSE; @@ -89,7 +91,7 @@ bool_t priTest() priBaseMod(mods, a, W_OF_B(521), i); while (i--) if (mods[i] != zzModW(a, W_OF_B(521), priBasePrime(i)) || - priBasePrime(i) < WORD_BIT_HALF && + priBasePrime(i) < WORD_MID && mods[i] != zzModW2(a, W_OF_B(521), priBasePrime(i))) return FALSE; // найти 2-битовое нечетное простое число @@ -132,7 +134,7 @@ bool_t priTest() if (priBaseSize() < 10 || sizeof(stack) < priExtendPrime_deep(289, W_OF_B(256), 0) || !priExtendPrime(p, 289, a, W_OF_B(256), SIZE_MAX, 0, prngCOMBOStepR, - combo_state, stack) || + state, stack) || sizeof(stack) < priIsPrime_deep(W_OF_B(256)) || !priIsPrime(p, W_OF_B(289), stack)) return FALSE; @@ -144,8 +146,9 @@ bool_t priTest() // проверить, что 2^256 - 29237 является простым Жермен memSet(a, 0xFF, O_OF_B(256)); a[0] = WORD_MAX - 29236; - if (sizeof(stack) < priIsSieved_deep(10) || - sizeof(stack) < priIsSGPrime_deep(W_OF_B(256)) || + if (sizeof(stack) < utilMax(2, + priIsSieved_deep(10), + priIsSGPrime_deep(W_OF_B(256))) || !priIsSieved(a, W_OF_B(256), 10, stack) || !priIsSGPrime(a, W_OF_B(256), stack) != 0) return FALSE; @@ -153,7 +156,7 @@ bool_t priTest() a[0] = 11; if (sizeof(stack) < priExtendPrime_deep(5, 1, 10) || !priExtendPrime(p, 5, a, 1, SIZE_MAX, 0, - prngCOMBOStepR, combo_state, stack) || + prngCOMBOStepR, state, stack) || p[0] != 23) return FALSE; // все нормально diff --git a/test/math/ww_test.c b/test/math/ww_test.c index 87f80e76..bc6c9366 100644 --- a/test/math/ww_test.c +++ b/test/math/ww_test.c @@ -4,7 +4,7 @@ \brief Tests for operations on arbitrary length words \project bee2/test \created 2023.03.31 -\version 2023.02.31 +\version 2025.07.24 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -26,30 +26,30 @@ bool_t wwTest() word c[8]; // заполнение и сравнение if ((wwSetW(a, COUNT_OF(a), 0), FALSE) || - !SAFE(wwIsZero)(a, 8) || !FAST(wwIsZero)(a, 8) || + !wwIsZero(a, 8) || !FAST(wwIsZero)(a, 8) || (wwSetZero(a, COUNT_OF(a)), FALSE) || - !SAFE(wwIsZero)(a, 8) || !FAST(wwIsZero)(a, 8) || + !wwIsZero(a, 8) || !FAST(wwIsZero)(a, 8) || (wwSetW(a, COUNT_OF(a), 0x36), FALSE) || - SAFE(wwIsZero)(a, 8) || FAST(wwIsZero)(a, 8) || - !SAFE(wwIsW)(a, 8, 0x36) || !FAST(wwIsW)(a, 8, 0x36) || - SAFE(wwIsW)(a, 8, 0x5C) || FAST(wwIsW)(a, 8, 0x5C) || - SAFE(wwCmpW)(a, 8, 0x36) != 0 || FAST(wwCmpW)(a, 8, 0x36) != 0 || - SAFE(wwCmpW)(a, 8, 0x5C) >=0 || FAST(wwCmpW)(a, 8, 0x5C) >= 0 || + wwIsZero(a, 8) || FAST(wwIsZero)(a, 8) || + !wwIsW(a, 8, 0x36) || !FAST(wwIsW)(a, 8, 0x36) || + wwIsW(a, 8, 0x5C) || FAST(wwIsW)(a, 8, 0x5C) || + wwCmpW(a, 8, 0x36) != 0 || FAST(wwCmpW)(a, 8, 0x36) != 0 || + wwCmpW(a, 8, 0x5C) >=0 || FAST(wwCmpW)(a, 8, 0x5C) >= 0 || (wwRepW(a, COUNT_OF(a), 0x36), FALSE) || - SAFE(wwIsZero)(a, 8) || FAST(wwIsZero)(a, 8) || - !SAFE(wwIsRepW)(a, 8, 0x36) || !FAST(wwIsRepW)(a, 8, 0x36) || - SAFE(wwIsRepW)(a, 8, 0x5C) || FAST(wwIsRepW)(a, 8, 0x5C)) + wwIsZero(a, 8) || FAST(wwIsZero)(a, 8) || + !wwIsRepW(a, 8, 0x36) || !FAST(wwIsRepW)(a, 8, 0x36) || + wwIsRepW(a, 8, 0x5C) || FAST(wwIsRepW)(a, 8, 0x5C)) return FALSE; // копирование и сравнение if ((wwCopy(a, a, 8), FALSE) || - !SAFE(wwEq)(a, a, 8) || !FAST(wwEq)(a, a, 8) || + !wwEq(a, a, 8) || !FAST(wwEq)(a, a, 8) || (wwRepW(b, 8, 0x5C), FALSE) || - SAFE(wwEq)(a, b, 8) || FAST(wwEq)(a, b, 8) || - SAFE(wwCmp)(a, b, 8) >= 0 || FAST(wwCmp)(a, b, 8) >= 0 || - SAFE(wwCmp2)(a, 8, b, 7) <= 0 || FAST(wwCmp2)(a, 8, b, 7) <= 0 || + wwEq(a, b, 8) || FAST(wwEq)(a, b, 8) || + wwCmp(a, b, 8) >= 0 || FAST(wwCmp)(a, b, 8) >= 0 || + wwCmp2(a, 8, b, 7) <= 0 || FAST(wwCmp2)(a, 8, b, 7) <= 0 || (wwSwap(a, b, 8), FALSE) || - SAFE(wwCmp)(a, b, 8) <= 0 || FAST(wwCmp)(a, b, 8) <= 0 || - SAFE(wwCmp2)(a, 7, b, 8) >= 0 || FAST(wwCmp2)(a, 7, b, 8) >= 0) + wwCmp(a, b, 8) <= 0 || FAST(wwCmp)(a, b, 8) <= 0 || + wwCmp2(a, 7, b, 8) >= 0 || FAST(wwCmp2)(a, 7, b, 8) >= 0) return FALSE; // операции с битами ASSERT(wwIsRepW(b, 8, 0x36)); diff --git a/test/math/zz_test.c b/test/math/zz_test.c index a17d23cc..da83172e 100644 --- a/test/math/zz_test.c +++ b/test/math/zz_test.c @@ -4,7 +4,7 @@ \brief Tests for multiple-precision unsigned integers \project bee2/test \created 2014.07.15 -\version 2025.05.07 +\version 2025.09.28 \copyright The Bee2 authors \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt). ******************************************************************************* @@ -31,23 +31,23 @@ static bool_t zzTestAdd() word b[n]; word c[n]; word c1[n]; - octet combo_state[32]; + octet state[32]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep()) + if (sizeof(state) < prngCOMBO_keep()) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // сложение / вычитание while (reps--) { word carry; - prngCOMBOStepR(a, O_OF_W(n), combo_state); - prngCOMBOStepR(b, O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(n), state); + prngCOMBOStepR(b, O_OF_W(n), state); // zzAdd / zzSub / zzIsSumEq carry = zzAdd(c, a, b, n); if (zzSub(c1, c, b, n) != carry || !wwEq(c1, a, n) || - SAFE(zzIsSumEq)(c, a, b, n) != wordEq(carry, 0) || + zzIsSumEq(c, a, b, n) != wordEq(carry, 0) || FAST(zzIsSumEq)(c, a, b, n) != wordEq(carry, 0)) return FALSE; // zzAdd2 / zzSub2 @@ -61,7 +61,7 @@ static bool_t zzTestAdd() carry = zzAddW(c, a, n, b[0]); if (zzSubW(c1, c, n, b[0]) != carry || !wwEq(c1, a, n) || - SAFE(zzIsSumWEq)(c, a, n, b[0]) != wordEq(carry, 0) || + zzIsSumWEq(c, a, n, b[0]) != wordEq(carry, 0) || FAST(zzIsSumWEq)(c, a, n, b[0]) != wordEq(carry, 0)) return FALSE; // zzAddW2 / zzSubW2 @@ -75,7 +75,7 @@ static bool_t zzTestAdd() carry = zzAddW(c, a, 1, b[0]); if (zzSubW(c1, c, 1, b[0]) != carry || !wwEq(c1, a, 1) || - SAFE(zzIsSumWEq)(c, a, 1, b[0]) != wordEq(carry, 0) || + zzIsSumWEq(c, a, 1, b[0]) != wordEq(carry, 0) || FAST(zzIsSumWEq)(c, a, 1, b[0]) != wordEq(carry, 0)) return FALSE; // zzAdd3 / zzAdd @@ -111,10 +111,10 @@ static bool_t zzTestMul() word c1[2 * n]; word b1[n + 1]; word r1[n]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || + if (sizeof(state) < prngCOMBO_keep() || sizeof(stack) < utilMax(4, zzMul_deep(n, n), zzSqr_deep(n), @@ -122,14 +122,14 @@ static bool_t zzTestMul() zzMod_deep(2 * n, n))) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // умножение / деление while (reps--) { size_t na, nb; word w; - prngCOMBOStepR(a, O_OF_W(n), combo_state); - prngCOMBOStepR(b, O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(n), state); + prngCOMBOStepR(b, O_OF_W(n), state); // zzSqr / zzMul for (na = 1; na <= n; ++na) { @@ -142,7 +142,7 @@ static bool_t zzTestMul() for (na = 1; na <= n; ++na) { a[na - 1] = a[na - 1] ? a[na - 1] : WORD_1; - zzRandMod(r, a, na, prngCOMBOStepR, combo_state); + zzRandMod(r, a, na, prngCOMBOStepR, state); for (nb = 1; nb <= n; ++nb) { zzMul(c, a, na, b, nb, stack); @@ -179,8 +179,8 @@ static bool_t zzTestMul() c[na + 1] = zzAddW(c, c, na + 1, r[0]); if (zzModW(c, na + 2, w) != r[0]) return FALSE; - w &= WORD_BIT_HALF - WORD_1; - w = w ? w : WORD_BIT_HALF; + w &= WORD_MID - WORD_1; + w = w ? w : WORD_MID; r[1] %= w; c[na] = zzMulW(c, a, na, w); c[na + 1] = zzAddW(c, c, na + 1, r[1]); @@ -193,14 +193,14 @@ static bool_t zzTestMul() ASSERT(n > 3); // переполнение частного, уточнение пробного частного b1[0] = b1[1] = WORD_MAX; - b[0] = WORD_MAX, b[1] = WORD_BIT_HI; + b[0] = WORD_MAX, b[1] = WORD_HI; zzMul(a, b, 2, b1, 2, stack); zzDiv(c1, r, a, 4, b, 2, stack); if (!wwIsZero(r, 2) || !wwEq(c1, b1, 2) || c1[2] != 0) return FALSE; // корректирующее сложение b1[0] = b1[1] = b1[2] = WORD_MAX; - b[0] = WORD_MAX, b[1] = 0, b[2] = WORD_BIT_HI; + b[0] = WORD_MAX, b[1] = 0, b[2] = WORD_HI; zzMul(a, b, 3, b1, 3, stack); zzDiv(c1, r, a, 6, b, 3, stack); if (!wwIsZero(r, 2) || !wwEq(c1, b1, 3) || c1[3] != 0) @@ -219,10 +219,10 @@ static bool_t zzTestMod() word t[n]; word t1[n]; word mod[n]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || + if (sizeof(state) < prngCOMBO_keep() || sizeof(stack) < utilMax(10, zzPowerMod_deep(n, 1), zzMulMod_deep(n), @@ -236,12 +236,12 @@ static bool_t zzTestMod() zzAlmostInvMod_deep(n))) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // возведение в степень wwRepW(mod, n, WORD_MAX); if (!zzIsOdd(mod, n) || zzIsEven(mod, n)) return FALSE; - if (!zzRandMod(a, mod, n, prngCOMBOStepR, combo_state)) + if (!zzRandMod(a, mod, n, prngCOMBOStepR, state)) return FALSE; b[0] = 3; zzPowerMod(t, a, n, b, 1, mod, stack); @@ -254,20 +254,20 @@ static bool_t zzTestMod() { size_t k; // генерация - prngCOMBOStepR(mod, O_OF_W(n), combo_state); - prngCOMBOStepR(a, O_OF_W(n), combo_state); - prngCOMBOStepR(b, O_OF_W(n), combo_state); + prngCOMBOStepR(mod, O_OF_W(n), state); + prngCOMBOStepR(a, O_OF_W(n), state); + prngCOMBOStepR(b, O_OF_W(n), state); if (mod[n - 1] == 0) mod[n - 1] = WORD_MAX; zzMod(a, a, n, mod, n, stack); zzMod(b, b, n, mod, n, stack); - // SAFE(zzAddMod) / SAFE(zzSubMod) - SAFE(zzAddMod)(t, a, b, mod, n); - SAFE(zzSubMod)(t1, t, b, mod, n); - if (!SAFE(wwEq)(t1, a, n)) + // zzAddMod / zzSubMod + zzAddMod(t, a, b, mod, n); + zzSubMod(t1, t, b, mod, n); + if (!wwEq(t1, a, n)) return FALSE; - SAFE(zzSubMod)(t1, t, a, mod, n); - if (!SAFE(wwEq)(t1, b, n)) + zzSubMod(t1, t, a, mod, n); + if (!wwEq(t1, b, n)) return FALSE; // FAST(zzAddMod) / FAST(zzSubMod) FAST(zzAddMod)(t, a, b, mod, n); @@ -277,23 +277,23 @@ static bool_t zzTestMod() FAST(zzSubMod)(t1, t, a, mod, n); if (!FAST(wwEq)(t1, b, n)) return FALSE; - // SAFE(zzAddWMod) / SAFE(zzSubWMod) - SAFE(zzAddWMod)(t, a, b[0], mod, n); - SAFE(zzSubWMod)(t1, t, b[0], mod, n); - if (!SAFE(wwEq)(t1, a, n)) + // zzAddWMod / zzSubWMod + zzAddWMod(t, a, b[0], mod, n); + zzSubWMod(t1, t, b[0], mod, n); + if (!wwEq(t1, a, n)) return FALSE; // FAST(zzAddWMod) / FAST(zzSubWMod) FAST(zzAddWMod)(t, a, b[0], mod, n); FAST(zzSubWMod)(t1, t, b[0], mod, n); if (!FAST(wwEq)(t1, a, n)) return FALSE; - // SAFE(zzNegMod) - SAFE(zzNegMod)(t, a, mod, n); - SAFE(zzAddMod)(t1, t, a, mod, n); - if (!SAFE(wwIsZero)(t1, n)) + // zzNegMod + zzNegMod(t, a, mod, n); + zzAddMod(t1, t, a, mod, n); + if (!wwIsZero(t1, n)) return FALSE; - SAFE(zzNegMod)(t1, t1, mod, n); - if (!SAFE(wwIsZero)(t1, n)) + zzNegMod(t1, t1, mod, n); + if (!wwIsZero(t1, n)) return FALSE; // FAST(zzNegMod) FAST(zzNegMod)(t, a, mod, n); @@ -303,11 +303,11 @@ static bool_t zzTestMod() FAST(zzNegMod)(t1, t1, mod, n); if (!FAST(wwIsZero)(t1, n)) return FALSE; - // SAFE(zzDoubleMod) / SAFE(zzHalfMod) + // zzDoubleMod / zzHalfMod mod[0] |= 1; - SAFE(zzHalfMod)(t, a, mod, n); - SAFE(zzDoubleMod)(t1, t, mod, n); - if (!SAFE(wwEq)(t1, a, n)) + zzHalfMod(t, a, mod, n); + zzDoubleMod(t1, t, mod, n); + if (!wwEq(t1, a, n)) return FALSE; // FAST(zzDoubleMod) / FAST(zzHalfMod) FAST(zzHalfMod)(t, a, mod, n); @@ -364,10 +364,10 @@ static bool_t zzTestGCD() word t1[2 * n]; word p[2 * n]; word p1[3 * n]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || + if (sizeof(state) < prngCOMBO_keep() || sizeof(stack) < utilMax(4, zzMul_deep(n, n), zzGCD_deep(n, n), @@ -375,14 +375,14 @@ static bool_t zzTestGCD() zzExGCD_deep(n, n))) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // эксперименты while (reps--) { size_t na, nb; // генерация - prngCOMBOStepR(a, O_OF_W(n), combo_state); - prngCOMBOStepR(b, O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(n), state); + prngCOMBOStepR(b, O_OF_W(n), state); a[0] = a[0] ? a[0] : 1; b[0] = b[0] ? b[0] : 2; // цикл по длинами @@ -417,10 +417,10 @@ static bool_t zzTestRed() word t1[2 * n]; word barr_param[n + 2]; word mod[n]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || + if (sizeof(state) < prngCOMBO_keep() || sizeof(stack) < utilMax(6, zzRed_deep(n), zzRedCrand_deep(n), @@ -430,13 +430,13 @@ static bool_t zzTestRed() zzRedCrandMont_deep(n))) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // редукция while (reps--) { // генерация - prngCOMBOStepR(mod, O_OF_W(n), combo_state); - prngCOMBOStepR(a, O_OF_W(2 * n), combo_state); + prngCOMBOStepR(mod, O_OF_W(n), state); + prngCOMBOStepR(a, O_OF_W(2 * n), state); mod[n - 1] = mod[n - 1] ? mod[n - 1] : 1; // zzRed / zzRedBarr wwCopy(t, a, 2 * n); @@ -451,12 +451,12 @@ static bool_t zzTestRed() FAST(zzRedBarr)(t1, mod, n, barr_param, stack); if (!wwEq(t1, t, n)) return FALSE; - // zzRed / SAFE(zzRedMont) + // zzRed / zzRedMont mod[0] |= 1; wwCopy(t, a, 2 * n); zzRed(t, mod, n, stack); wwCopy(t1, a, 2 * n); - SAFE(zzRedMont)(t1, mod, n, wordNegInv(mod[0]), stack); + zzRedMont(t1, mod, n, wordNegInv(mod[0]), stack); wwCopy(t1 + n, t1, n); wwSetZero(t1, n); zzRed(t1, mod, n, stack); @@ -470,12 +470,12 @@ static bool_t zzTestRed() zzRed(t1, mod, n, stack); if (!wwEq(t1, t, n)) return FALSE; - // zzRed / SAFE(zzRedCrand) + // zzRed / zzRedCrand wwRepW(mod + 1, n - 1, WORD_MAX); wwCopy(t, a, 2 * n); zzRed(t, mod, n, stack); wwCopy(t1, a, 2 * n); - SAFE(zzRedCrand)(t1, mod, n, stack); + zzRedCrand(t1, mod, n, stack); if (!wwEq(t1, t, n)) return FALSE; // zzRed / FAST(zzRedCrand) @@ -483,12 +483,12 @@ static bool_t zzTestRed() FAST(zzRedCrand)(t1, mod, n, stack); if (!wwEq(t1, t, n)) return FALSE; - // SAFE(zzRedMont) / SAFE(zzRedCrandMont) + // zzRedMont / zzRedCrandMont wwCopy(t, a, 2 * n); wwCopy(t1, a, 2 * n); - SAFE(zzRedMont)(t, mod, n, wordNegInv(mod[0]), stack); - SAFE(zzRedCrandMont)(t1, mod, n, wordNegInv(mod[0]), stack); - if (!SAFE(wwEq)(t1, t, n)) + zzRedMont(t, mod, n, wordNegInv(mod[0]), stack); + zzRedCrandMont(t1, mod, n, wordNegInv(mod[0]), stack); + if (!wwEq(t1, t, n)) return FALSE; // FAST(zzRedMont) / FAST(zzRedCrandMont) wwCopy(t, a, 2 * n); @@ -509,23 +509,23 @@ static bool_t zzTestEtc() word a[n]; word b[2 * n]; word t[(2 * n + 1) / 2]; - octet combo_state[32]; - octet stack[2048]; + mem_align_t state[64 / sizeof(mem_align_t)]; + mem_align_t stack[2048 / sizeof(mem_align_t)]; // подготовить память - if (sizeof(combo_state) < prngCOMBO_keep() || + if (sizeof(state) < prngCOMBO_keep() || sizeof(stack) < utilMax(3, zzSqr_deep(n), zzSqrt_deep(n), zzJacobi_deep(2 * n, n))) return FALSE; // инициализировать генератор COMBO - prngCOMBOStart(combo_state, utilNonce32()); + prngCOMBOStart(state, utilNonce32()); // символ Якоби while (reps1--) { - prngCOMBOStepR(a, O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(n), state); zzSqr(b, a, n, stack); - prngCOMBOStepR(t, O_OF_W(n), combo_state); + prngCOMBOStepR(t, O_OF_W(n), state); t[0] |= 1; // (a^2 / t) != -1? if (zzJacobi(b, 2 * n, t, n, stack) == -1) @@ -534,7 +534,7 @@ static bool_t zzTestEtc() // квадратные корни while (reps2--) { - prngCOMBOStepR(a, O_OF_W(n), combo_state); + prngCOMBOStepR(a, O_OF_W(n), state); // sqrt(a^2) == a? zzSqr(b, a, n, stack); zzSqrt(t, b, 2 * n, stack); diff --git a/win/vs09/cmd.vcproj b/win/vs09/cmd.vcproj index 92b25e1f..ae97b9bb 100644 --- a/win/vs09/cmd.vcproj +++ b/win/vs09/cmd.vcproj @@ -350,6 +350,14 @@ > + + + + - - @@ -728,15 +724,15 @@ Name="bign" > + + + + + + + + + + diff --git a/win/vs15/cmd.vcxproj b/win/vs15/cmd.vcxproj index cfc08dc2..44075bfb 100644 --- a/win/vs15/cmd.vcxproj +++ b/win/vs15/cmd.vcxproj @@ -532,6 +532,7 @@ + diff --git a/win/vs15/cmd.vcxproj.filters b/win/vs15/cmd.vcxproj.filters index d6433eb4..973761d6 100644 --- a/win/vs15/cmd.vcxproj.filters +++ b/win/vs15/cmd.vcxproj.filters @@ -51,6 +51,9 @@ {8ead9d74-e892-4ce5-9ff2-75f219e0168f} + + {357cb2f9-dbc4-4c7c-8467-86e44a8016fb} + @@ -134,6 +137,9 @@ Source Files\core + + Source Files\fmt + diff --git a/win/vs15/libbee2.vcxproj b/win/vs15/libbee2.vcxproj index 47b519fa..bef29acb 100644 --- a/win/vs15/libbee2.vcxproj +++ b/win/vs15/libbee2.vcxproj @@ -373,7 +373,10 @@ - + + + + @@ -399,7 +402,7 @@ - + diff --git a/win/vs15/libbee2.vcxproj.filters b/win/vs15/libbee2.vcxproj.filters index 9562d925..3c84ff99 100644 --- a/win/vs15/libbee2.vcxproj.filters +++ b/win/vs15/libbee2.vcxproj.filters @@ -49,6 +49,9 @@ {669eff52-7fc5-4c8a-94df-a1881f5218d5} + + {0b5a3a20-08c0-4130-8991-a0a96f8c4c7f} + @@ -108,9 +111,6 @@ Source Files\core - - Source Files\crypto - Source Files\crypto @@ -276,9 +276,6 @@ Source Files\crypto\bign - - Source Files\crypto\bign - Source Files\crypto\bign @@ -306,6 +303,21 @@ Source Files\core + + Source Files\crypto\bign + + + Source Files\crypto\bake + + + Source Files\crypto\bake + + + Source Files\crypto\bake + + + Source Files\crypto\bake +