SSE2/AVX dynamic support + progress (#195)

This commit is contained in:
TheTank20 authored and GitHub committed 2026-11-11 18:59:59 -05:00
1 parent 569f4b59f0
commit 769a3dfe23
18 files changed
+855 -122

No files matched your search

+58
View File
@@ -149,6 +149,8 @@ set(UMSKT_SOURCES
src/cli.cpp
src/windows/json.cpp
${UMSKT_KEYS_EMBED}
src/crypto/cpu_features.cpp
src/crypto/bn_kernels_scalar.cpp
src/crypto/mini_bn.cpp
src/crypto/mini_ec.cpp
src/crypto/mini_rand.cpp
@@ -255,6 +257,62 @@ if (UMSKT_FREESTANDING)
endif()
target_link_libraries(umskt PRIVATE kernel32)
if (UMSKT_WIN_X86)
add_library(umskt_bn_kernels_sse2 OBJECT src/crypto/bn_kernels_sse2.cpp)
target_include_directories(umskt_bn_kernels_sse2 PRIVATE "${CMAKE_SOURCE_DIR}/src/crypto")
target_compile_definitions(umskt_bn_kernels_sse2 PRIVATE
UMSKT_FREESTANDING
UMSKT_HAVE_SSE2_KERNELS
NDEBUG
)
target_compile_options(umskt_bn_kernels_sse2 PRIVATE
-m32
-O2
-ffreestanding
-fno-exceptions
-fno-rtti
-fno-threadsafe-statics
-fno-use-cxa-atexit
-fno-stack-protector
-fno-unwind-tables
-fno-asynchronous-unwind-tables
-msse2
-mfpmath=sse
)
target_compile_definitions(umskt PRIVATE UMSKT_HAVE_SSE2_KERNELS)
target_link_libraries(umskt PRIVATE umskt_bn_kernels_sse2)
message(STATUS "[UMSKT] SSE2 BN kernels enabled with runtime CPU/OS dispatch")
endif()
add_library(umskt_bn_kernels_avx2 OBJECT src/crypto/bn_kernels_avx2.cpp)
target_include_directories(umskt_bn_kernels_avx2 PRIVATE "${CMAKE_SOURCE_DIR}/src/crypto")
target_compile_definitions(umskt_bn_kernels_avx2 PRIVATE
UMSKT_FREESTANDING
UMSKT_HAVE_AVX2_KERNELS
NDEBUG
)
set(UMSKT_AVX2_FLAGS
-O2
-ffreestanding
-fno-exceptions
-fno-rtti
-fno-threadsafe-statics
-fno-use-cxa-atexit
-fno-stack-protector
-fno-unwind-tables
-fno-asynchronous-unwind-tables
-mavx2
)
if (UMSKT_WIN_X86)
list(APPEND UMSKT_AVX2_FLAGS -m32)
else()
list(APPEND UMSKT_AVX2_FLAGS -m64)
endif()
target_compile_options(umskt_bn_kernels_avx2 PRIVATE ${UMSKT_AVX2_FLAGS})
target_compile_definitions(umskt PRIVATE UMSKT_HAVE_AVX2_KERNELS)
target_link_libraries(umskt PRIVATE umskt_bn_kernels_avx2)
message(STATUS "[UMSKT] AVX2 BN kernels enabled with runtime CPU/OS dispatch")
get_filename_component(UMSKT_GCC_BIN "${CMAKE_CXX_COMPILER}" DIRECTORY)
find_program(UMSKT_OBJDUMP NAMES objdump HINTS "${UMSKT_GCC_BIN}")
if (UMSKT_OBJDUMP)
+4 -3
View File
@@ -55,11 +55,12 @@ In light of the recent exponential interest in this project I've decided to put
* Any DOS-based version of Windows
* Windows NT 4.0 or later (via NTVDM)
#### Windows (x86)
* Pentium processor or better
* Pentium processor or better (Pentium 4 recommended, Haswell or equivalent best)
* Windows 98 First Edition or later
* Windows NT 4.0 SP6a or later
* Windows NT 4.0 or later
#### Windows (x64)
* Windows MT 5.2 (Windows XP x64, Windows Server 2003) or later
* Windows NT 5.2 (Windows XP x64, Windows Server 2003) or later
* Haswell or equivalent recommended
#### Windows (ARM64)
* Winodws 11 21H2 or later
#### macOS
+202 -1
View File
@@ -57,6 +57,7 @@ struct Options {
int nonewlines;
int overrideVersion;
int nodashes;
int progress;
int instidFromStdin;
MODE applicationMode;
ACTIVATION_ALGORITHM activationMode;
@@ -88,6 +89,144 @@ static void outf(const char *fmt, ...) {
out_text(buffer);
}
static void err_text(const char *text) {
if (!text) {
return;
}
#ifdef UMSKT_FREESTANDING
uint32_t wrote = 0;
void *handle = GetStdHandle(UMSKT_STD_ERROR_HANDLE);
if (handle == NULL || handle == UMSKT_INVALID_HANDLE) {
return;
}
WriteFile(handle, text, (uint32_t)strlen(text), &wrote, NULL);
#else
fputs(text, stderr);
fflush(stderr);
#endif
}
struct ProgressCtx {
unsigned key_index;
unsigned key_count;
int last_percent;
int last_phase;
int active;
int verbose_layout;
int line_open;
};
static ProgressCtx g_progress_ctx;
static const unsigned PROGRESS_LINE_WIDTH = 72;
static void progress_write_padded(const char *body) {
char line[80];
unsigned i;
unsigned len = 0;
line[0] = '\r';
while (body[len] && len < PROGRESS_LINE_WIDTH) {
line[1 + len] = body[len];
len++;
}
for (i = len; i < PROGRESS_LINE_WIDTH; i++) {
line[1 + i] = ' ';
}
line[1 + PROGRESS_LINE_WIDTH] = 0;
err_text(line);
g_progress_ctx.line_open = 1;
}
static void progress_clear_line(void) {
if (g_progress_ctx.line_open) {
progress_write_padded("");
err_text("\r");
g_progress_ctx.line_open = 0;
}
}
static void progress_break_line(void) {
if (g_progress_ctx.line_open) {
progress_write_padded("");
err_text("\n");
g_progress_ctx.line_open = 0;
}
g_progress_ctx.last_phase = -1;
g_progress_ctx.last_percent = -1;
}
static const char *progress_phase_label(int phase) {
const char *op = UMSKT::getProgressLabel();
if (g_progress_ctx.verbose_layout && op && op[0]) {
return op;
}
if (phase == UMSKT_PROGRESS_GEN) {
return "Generating key";
}
if (phase == UMSKT_PROGRESS_VERIFY) {
return "Validating key";
}
return "Multiplying elliptic curve";
}
static void progress_draw_bar(int phase, unsigned current, unsigned total) {
char body[80];
unsigned percent;
unsigned filled;
unsigned i;
const unsigned width = 24;
const char *label;
if (total == 0) {
return;
}
if (current > total) {
current = total;
}
percent = (current * 100u) / total;
if (g_progress_ctx.last_phase == phase &&
(int)percent == g_progress_ctx.last_percent &&
current != total &&
current != 0 &&
current != 1) {
return;
}
g_progress_ctx.last_phase = phase;
g_progress_ctx.last_percent = (int)percent;
filled = (current * width) / total;
body[0] = '[';
for (i = 0; i < width; i++) {
body[1 + i] = (i < filled) ? '#' : '-';
}
label = progress_phase_label(phase);
if (g_progress_ctx.key_count > 1) {
snprintf(body + 1 + width, sizeof(body) - (1 + width),
"] %3u%% %s (%u/%u)",
percent, label, g_progress_ctx.key_index + 1, g_progress_ctx.key_count);
} else {
snprintf(body + 1 + width, sizeof(body) - (1 + width),
"] %3u%% %s", percent, label);
}
progress_write_padded(body);
}
static void progress_callback(int phase, unsigned current, unsigned total, void *user) {
ProgressCtx *ctx = (ProgressCtx *)user;
if (!ctx || !ctx->active) {
return;
}
if (phase == UMSKT_PROGRESS_BREAK) {
progress_break_line();
return;
}
if (ctx->verbose_layout && ctx->last_phase != -1 && ctx->last_phase != phase) {
progress_break_line();
}
if (phase == UMSKT_PROGRESS_MUL ||
phase == UMSKT_PROGRESS_GEN ||
phase == UMSKT_PROGRESS_VERIFY) {
progress_draw_bar(phase, current, total);
}
}
static int streq(const char *a, const char *b) {
return strcmp(a, b) == 0;
}
@@ -315,7 +454,8 @@ static void show_help(char *argv[]) {
out_text("\t-V --validate\tproduct key to validate signature\n");
out_text("\t-N --nonewlines\tdisables newlines (for easier embedding in other apps)\n");
out_text("\t-o --override\tDisables version check for confirmation IDs, if you need this send an issue on GitHub\n");
out_text("\t-D --nodashes\tDisables dashes in product keys and confirmation IDs (for easier copy-pasting)");
out_text("\t-D --nodashes\tDisables dashes in product keys and confirmation IDs (for easier copy-pasting)\n");
out_text("\t-P --progress\tDisplays progress bar (for long-running operations)\n");
out_text("\n");
}
@@ -445,6 +585,8 @@ static int parse_command_line(int argc, char *argv[], Options *options) {
options->overrideVersion = 1;
} else if (streq(arg, "-D") || streq(arg, "--nodashes")) {
options->nodashes = 1;
} else if (streq(arg, "-P") || streq(arg, "--progress")) {
options->progress = 1;
} else {
options->error = 1;
}
@@ -691,10 +833,34 @@ static int run_keys(Options *options, const char *json, int length) {
print_id(&nRaw);
}
BN_sub(privateKey, genOrder, privateKey);
if (options->progress) {
g_progress_ctx.key_index = 0;
g_progress_ctx.key_count = (unsigned)options->numKeys;
g_progress_ctx.last_percent = -1;
g_progress_ctx.last_phase = -1;
g_progress_ctx.active = 1;
g_progress_ctx.verbose_layout = options->verbose;
g_progress_ctx.line_open = 0;
UMSKT::setProgress(progress_callback, &g_progress_ctx);
}
for (i = 0; i < total; i++) {
int valid;
if (options->progress) {
g_progress_ctx.key_index = (unsigned)count;
g_progress_ctx.last_percent = -1;
g_progress_ctx.last_phase = -1;
}
PIDGEN3::BINK1998::Generate(eCurve, genPoint, genOrder, privateKey, nRaw, options->upgrade, pKey);
if (options->progress) {
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_VERIFY);
UMSKT::setMulProgress(1);
}
valid = PIDGEN3::BINK1998::Verify(eCurve, genPoint, pubPoint, pKey);
if (options->progress) {
UMSKT::setMulProgress(0);
UMSKT::setProgressLabel(NULL);
progress_clear_line();
}
if (valid) {
print_key(pKey, options->nodashes);
if (i < total - 1 || options->verbose) {
@@ -716,10 +882,24 @@ static int run_keys(Options *options, const char *json, int length) {
}
}
}
if (options->progress) {
UMSKT::setProgress(NULL, NULL);
g_progress_ctx.active = 0;
}
} else if (options->applicationMode == MODE_BINK2002_GENERATE) {
if (options->verbose) {
outf("> Channel ID: %03d\n", options->channelID);
}
if (options->progress) {
g_progress_ctx.key_index = 0;
g_progress_ctx.key_count = (unsigned)options->numKeys;
g_progress_ctx.last_percent = -1;
g_progress_ctx.last_phase = -1;
g_progress_ctx.active = 1;
g_progress_ctx.verbose_layout = options->verbose;
g_progress_ctx.line_open = 0;
UMSKT::setProgress(progress_callback, &g_progress_ctx);
}
for (i = 0; i < total; i++) {
DWORD pAuthInfo = 0;
int valid;
@@ -728,8 +908,22 @@ static int run_keys(Options *options, const char *json, int length) {
if (options->verbose) {
outf("> AuthInfo: %u\n", pAuthInfo);
}
if (options->progress) {
g_progress_ctx.key_index = (unsigned)count;
g_progress_ctx.last_percent = -1;
g_progress_ctx.last_phase = -1;
}
PIDGEN3::BINK2002::Generate(eCurve, genPoint, genOrder, privateKey, (DWORD)options->channelID, pAuthInfo, options->upgrade, (DWORD)options->serialMin, (DWORD)options->serialMax, pKey);
if (options->progress) {
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_VERIFY);
UMSKT::setMulProgress(1);
}
valid = PIDGEN3::BINK2002::Verify(eCurve, genPoint, pubPoint, NULL, pKey);
if (options->progress) {
UMSKT::setMulProgress(0);
UMSKT::setProgressLabel(NULL);
progress_clear_line();
}
if (valid) {
print_key(pKey, options->nodashes);
if (i < total - 1 || options->verbose) {
@@ -751,6 +945,10 @@ static int run_keys(Options *options, const char *json, int length) {
}
}
}
if (options->progress) {
UMSKT::setProgress(NULL, NULL);
g_progress_ctx.active = 0;
}
} else if (options->applicationMode == MODE_BINK1998_VALIDATE || options->applicationMode == MODE_BINK2002_VALIDATE) {
char product_key[PK_LENGTH + NULL_TERMINATOR];
memset(product_key, 0, sizeof(product_key));
@@ -798,6 +996,9 @@ static int run_keys(Options *options, const char *json, int length) {
}
if (gaveUp || count < options->numKeys) {
if (options->progress) {
progress_clear_line();
}
out_text("ERROR: failed to generate a valid product key\n");
curve_free(&curve);
BN_free(privateKey);
+35
View File
@@ -0,0 +1,35 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef UMSKT_BN_KERNELS_H
#define UMSKT_BN_KERNELS_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void umskt_mont_mul_scalar(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw);
void umskt_bn_mul_limbs_scalar(uint32_t *r, const uint32_t *a, int an, const uint32_t *b, int bn);
#if defined(UMSKT_HAVE_SSE2_KERNELS)
void umskt_mont_mul_sse2(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw);
void umskt_bn_mul_limbs_sse2(uint32_t *r, const uint32_t *a, int an, const uint32_t *b, int bn);
#endif
#if defined(UMSKT_HAVE_AVX2_KERNELS)
void umskt_mont_mul_avx2(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw);
void umskt_bn_mul_limbs_avx2(uint32_t *r, const uint32_t *a, int an, const uint32_t *b, int bn);
#endif
void umskt_bn_dispatch_init(void);
#ifdef __cplusplus
}
#endif
#endif
+100
View File
@@ -0,0 +1,100 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#ifndef BN_KERNEL_SUFFIX
#error "BN_KERNEL_SUFFIX must be defined before including bn_kernels.inc.cpp"
#endif
#define BN_KERNEL_PASTE2(a, b) a##_##b
#define BN_KERNEL_PASTE(a, b) BN_KERNEL_PASTE2(a, b)
#define BN_KERNEL_FN(name) BN_KERNEL_PASTE(name, BN_KERNEL_SUFFIX)
void BN_KERNEL_FN(umskt_mont_mul)(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw) {
uint32_t tmp[34];
int i;
int j;
int ge;
for (i = 0; i < nw + 2; i++) {
tmp[i] = 0;
}
for (i = 0; i < nw; i++) {
uint64_t carry = 0;
uint32_t m;
for (j = 0; j < nw; j++) {
carry += (uint64_t)tmp[j] + (uint64_t)a[j] * b[i];
tmp[j] = (uint32_t)carry;
carry >>= 32;
}
carry += tmp[nw];
tmp[nw] = (uint32_t)carry;
tmp[nw + 1] = (uint32_t)(carry >> 32);
m = tmp[0] * n0;
carry = 0;
for (j = 0; j < nw; j++) {
carry += (uint64_t)tmp[j] + (uint64_t)m * n[j];
tmp[j] = (uint32_t)carry;
carry >>= 32;
}
carry += tmp[nw];
tmp[nw] = (uint32_t)carry;
tmp[nw + 1] += (uint32_t)(carry >> 32);
for (j = 0; j <= nw; j++) {
tmp[j] = tmp[j + 1];
}
tmp[nw + 1] = 0;
}
ge = tmp[nw] != 0;
if (!ge) {
for (i = nw - 1; i >= 0; i--) {
if (tmp[i] != n[i]) {
ge = tmp[i] > n[i];
break;
}
if (i == 0) {
ge = 1;
}
}
}
if (ge) {
uint32_t borrow = 0;
for (i = 0; i < nw; i++) {
uint64_t sub = (uint64_t)n[i] + borrow;
r[i] = (uint32_t)((uint64_t)tmp[i] - sub);
borrow = (uint64_t)tmp[i] < sub;
}
} else {
for (i = 0; i < nw; i++) {
r[i] = tmp[i];
}
}
}
void BN_KERNEL_FN(umskt_bn_mul_limbs)(uint32_t *r, const uint32_t *a, int an, const uint32_t *b, int bn) {
int i;
int j;
int top = an + bn;
for (i = 0; i < top + 1; i++) {
r[i] = 0;
}
for (i = 0; i < an; i++) {
uint32_t carry = 0;
for (j = 0; j < bn; j++) {
union {
uint64_t v;
uint32_t p[2];
} acc;
acc.v = (uint64_t)a[i] * b[j] + r[i + j] + carry;
r[i + j] = acc.p[0];
carry = acc.p[1];
}
r[i + bn] = carry;
}
}
#undef BN_KERNEL_FN
#undef BN_KERNEL_PASTE
#undef BN_KERNEL_PASTE2
+11
View File
@@ -0,0 +1,11 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "bn_kernels.h"
#define BN_KERNEL_SUFFIX avx2
#include "bn_kernels.inc.cpp"
#undef BN_KERNEL_SUFFIX
+11
View File
@@ -0,0 +1,11 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "bn_kernels.h"
#define BN_KERNEL_SUFFIX scalar
#include "bn_kernels.inc.cpp"
#undef BN_KERNEL_SUFFIX
+11
View File
@@ -0,0 +1,11 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "bn_kernels.h"
#define BN_KERNEL_SUFFIX sse2
#include "bn_kernels.inc.cpp"
#undef BN_KERNEL_SUFFIX
+189
View File
@@ -0,0 +1,189 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "cpu_features.h"
#if defined(UMSKT_FREESTANDING) || defined(_WIN32)
#ifndef WINVER
#define WINVER 0x0400
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#ifndef PF_XMMI64_INSTRUCTIONS_AVAILABLE
#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10
#endif
#ifndef PF_AVX2_INSTRUCTIONS_AVAILABLE
#define PF_AVX2_INSTRUCTIONS_AVAILABLE 40
#endif
#endif
static int g_cpu_ready = 0;
static int g_has_sse2 = 0;
static int g_has_avx2 = 0;
#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
#if defined(__GNUC__) || defined(__clang__)
static int cpuid_supported(void) {
#if defined(__x86_64__) || defined(_M_X64)
return 1;
#else
unsigned int original;
unsigned int modified;
__asm__ __volatile__(
"pushfl\n\t"
"popl %0\n\t"
"movl %0, %1\n\t"
"xorl $0x200000, %0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"pushl %1\n\t"
"popfl\n\t"
: "=&r"(modified), "=&r"(original)
:
: "cc");
return ((original ^ modified) & 0x200000u) != 0;
#endif
}
static void do_cpuid(unsigned int leaf, unsigned int subleaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
__asm__ __volatile__(
"cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(leaf), "c"(subleaf));
}
static unsigned long long do_xgetbv(unsigned int index) {
unsigned int eax;
unsigned int edx;
__asm__ __volatile__(
".byte 0x0f, 0x01, 0xd0"
: "=a"(eax), "=d"(edx)
: "c"(index));
return ((unsigned long long)edx << 32) | eax;
}
#else
static int cpuid_supported(void) {
return 0;
}
static void do_cpuid(unsigned int leaf, unsigned int subleaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) {
(void)leaf;
(void)subleaf;
*eax = *ebx = *ecx = *edx = 0;
}
static unsigned long long do_xgetbv(unsigned int index) {
(void)index;
return 0;
}
#endif
static int cpu_has_sse2_bit(void) {
unsigned int eax = 0;
unsigned int ebx = 0;
unsigned int ecx = 0;
unsigned int edx = 0;
if (!cpuid_supported()) {
return 0;
}
do_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
if (eax < 1) {
return 0;
}
do_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
return (edx & (1u << 26)) != 0;
}
static int cpu_has_avx2_bits(void) {
unsigned int eax = 0;
unsigned int ebx = 0;
unsigned int ecx = 0;
unsigned int edx = 0;
unsigned long long xcr0;
if (!cpuid_supported()) {
return 0;
}
do_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
if (eax < 1) {
return 0;
}
do_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
/* OSXSAVE (27) and AVX (28) */
if ((ecx & ((1u << 27) | (1u << 28))) != ((1u << 27) | (1u << 28))) {
return 0;
}
xcr0 = do_xgetbv(0);
/* XMM (bit 1) and YMM (bit 2) state must be enabled by the OS. */
if ((xcr0 & 0x6ull) != 0x6ull) {
return 0;
}
do_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
if (eax < 7) {
return 0;
}
do_cpuid(7, 0, &eax, &ebx, &ecx, &edx);
return (ebx & (1u << 5)) != 0;
}
static int os_supports_sse2(void) {
#if defined(UMSKT_FREESTANDING) || defined(_WIN32)
return IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) ? 1 : 0;
#else
return 1;
#endif
}
static int os_supports_avx2(void) {
#if defined(UMSKT_FREESTANDING) || defined(_WIN32)
return IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE) ? 1 : 0;
#else
return 1;
#endif
}
#else
static int cpu_has_sse2_bit(void) {
return 0;
}
static int cpu_has_avx2_bits(void) {
return 0;
}
static int os_supports_sse2(void) {
return 0;
}
static int os_supports_avx2(void) {
return 0;
}
#endif
void umskt_cpu_init(void) {
if (g_cpu_ready) {
return;
}
g_has_sse2 = cpu_has_sse2_bit() && os_supports_sse2();
g_has_avx2 = cpu_has_avx2_bits() && os_supports_avx2();
g_cpu_ready = 1;
}
int umskt_cpu_has_sse2(void) {
umskt_cpu_init();
return g_has_sse2;
}
int umskt_cpu_has_avx2(void) {
umskt_cpu_init();
return g_has_avx2;
}
+22
View File
@@ -0,0 +1,22 @@
/* This file is a part of the UMSKT Project.
*
* Copyleft (C) 2019-2026 UMSKT Contributors (et.al.)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef UMSKT_CPU_FEATURES_H
#define UMSKT_CPU_FEATURES_H
#ifdef __cplusplus
extern "C" {
#endif
void umskt_cpu_init(void);
int umskt_cpu_has_sse2(void);
int umskt_cpu_has_avx2(void);
#ifdef __cplusplus
}
#endif
#endif
+42 -75
View File
@@ -9,10 +9,48 @@
*/
#include "mini_openssl.h"
#include "bn_kernels.h"
#include "cpu_features.h"
#include <stdlib.h>
#include <string.h>
typedef void (*umskt_mont_mul_fn)(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw);
typedef void (*umskt_bn_mul_limbs_fn)(uint32_t *r, const uint32_t *a, int an, const uint32_t *b, int bn);
static umskt_mont_mul_fn g_mont_mul = umskt_mont_mul_scalar;
static umskt_bn_mul_limbs_fn g_bn_mul_limbs = umskt_bn_mul_limbs_scalar;
static int g_bn_dispatch_ready = 0;
void umskt_bn_dispatch_init(void) {
if (g_bn_dispatch_ready) {
return;
}
umskt_cpu_init();
#if defined(UMSKT_HAVE_AVX2_KERNELS)
if (umskt_cpu_has_avx2()) {
g_mont_mul = umskt_mont_mul_avx2;
g_bn_mul_limbs = umskt_bn_mul_limbs_avx2;
} else
#endif
#if defined(UMSKT_HAVE_SSE2_KERNELS)
if (umskt_cpu_has_sse2()) {
g_mont_mul = umskt_mont_mul_sse2;
g_bn_mul_limbs = umskt_bn_mul_limbs_sse2;
} else
#endif
{
(void)0;
}
g_bn_dispatch_ready = 1;
}
static void bn_dispatch_ensure(void) {
if (!g_bn_dispatch_ready) {
umskt_bn_dispatch_init();
}
}
struct bignum_st {
uint32_t *d;
int top;
@@ -505,8 +543,6 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
}
static int bn_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
int i;
int j;
int top = a->top + b->top;
if (a->top == 0 || b->top == 0) {
return BN_zero(r);
@@ -514,22 +550,8 @@ static int bn_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
if (!bn_wexpand(r, top + 1)) {
return 0;
}
for (i = 0; i < top + 1; i++) {
r->d[i] = 0;
}
for (i = 0; i < a->top; i++) {
uint32_t carry = 0;
for (j = 0; j < b->top; j++) {
union {
uint64_t v;
uint32_t p[2];
} acc;
acc.v = (uint64_t)a->d[i] * b->d[j] + r->d[i + j] + carry;
r->d[i + j] = acc.p[0];
carry = acc.p[1];
}
r->d[i + b->top] = carry;
}
bn_dispatch_ensure();
g_bn_mul_limbs(r->d, a->d, a->top, b->d, b->top);
r->top = top;
r->neg = (a->neg ^ b->neg) && 1;
bn_fix_top(r);
@@ -728,63 +750,8 @@ static void mont_load(uint32_t *dst, const BIGNUM *src, int nw) {
}
static void mont_mul(uint32_t *r, const uint32_t *a, const uint32_t *b, const uint32_t *n, uint32_t n0, int nw) {
uint32_t tmp[34];
int i;
int j;
int ge;
for (i = 0; i < nw + 2; i++) {
tmp[i] = 0;
}
for (i = 0; i < nw; i++) {
uint64_t carry = 0;
uint32_t m;
for (j = 0; j < nw; j++) {
carry += (uint64_t)tmp[j] + (uint64_t)a[j] * b[i];
tmp[j] = (uint32_t)carry;
carry >>= 32;
}
carry += tmp[nw];
tmp[nw] = (uint32_t)carry;
tmp[nw + 1] = (uint32_t)(carry >> 32);
m = tmp[0] * n0;
carry = 0;
for (j = 0; j < nw; j++) {
carry += (uint64_t)tmp[j] + (uint64_t)m * n[j];
tmp[j] = (uint32_t)carry;
carry >>= 32;
}
carry += tmp[nw];
tmp[nw] = (uint32_t)carry;
tmp[nw + 1] += (uint32_t)(carry >> 32);
for (j = 0; j <= nw; j++) {
tmp[j] = tmp[j + 1];
}
tmp[nw + 1] = 0;
}
ge = tmp[nw] != 0;
if (!ge) {
for (i = nw - 1; i >= 0; i--) {
if (tmp[i] != n[i]) {
ge = tmp[i] > n[i];
break;
}
if (i == 0) {
ge = 1;
}
}
}
if (ge) {
uint32_t borrow = 0;
for (i = 0; i < nw; i++) {
uint64_t sub = (uint64_t)n[i] + borrow;
r[i] = (uint32_t)((uint64_t)tmp[i] - sub);
borrow = (uint64_t)tmp[i] < sub;
}
} else {
for (i = 0; i < nw; i++) {
r[i] = tmp[i];
}
}
bn_dispatch_ensure();
g_mont_mul(r, a, b, n, n0, nw);
}
static int bn_to_mont_rr(BIGNUM *rr, const BIGNUM *m, int nw) {
+7
View File
@@ -12,6 +12,10 @@
#include <stdlib.h>
#include <string.h>
extern "C" int umskt_mul_progress_enabled(void);
extern "C" int umskt_ec_progress_phase(void);
extern "C" void umskt_report_progress(int phase, unsigned current, unsigned total);
struct ec_group_st {
BIGNUM *p;
BIGNUM *a;
@@ -421,6 +425,9 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_P
if (ok && BN_is_bit_set(m, i)) {
ok = jadd_mixed(group, &acc, q);
}
if (ok && umskt_mul_progress_enabled() && bits > 0) {
umskt_report_progress(umskt_ec_progress_phase(), (unsigned)(bits - i), (unsigned)bits);
}
}
if (ok) {
ok = jto_affine(group, r, &acc);
+65
View File
@@ -22,6 +22,69 @@
#include "libumskt.h"
static UMSKT::ProgressFn g_progress_fn = NULL;
static void *g_progress_user = NULL;
static int g_mul_progress = 0;
static int g_ec_progress_phase = UMSKT_PROGRESS_MUL;
static int g_progress_suspended = 0;
static char g_progress_label[24];
void UMSKT::setProgress(ProgressFn fn, void *user) {
g_progress_fn = fn;
g_progress_user = user;
}
void UMSKT::setMulProgress(int on) {
g_mul_progress = on ? 1 : 0;
}
void UMSKT::setEcProgressPhase(int phase) {
g_ec_progress_phase = phase;
}
void UMSKT::setProgressLabel(const char *label) {
size_t i = 0;
if (!label) {
g_progress_label[0] = 0;
return;
}
while (label[i] && i + 1 < sizeof(g_progress_label)) {
g_progress_label[i] = label[i];
i++;
}
g_progress_label[i] = 0;
}
const char *UMSKT::getProgressLabel(void) {
return g_progress_label;
}
extern "C" int umskt_mul_progress_enabled(void) {
return g_mul_progress && g_progress_fn != NULL;
}
extern "C" int umskt_ec_progress_phase(void) {
return g_ec_progress_phase;
}
extern "C" void umskt_report_progress(int phase, unsigned current, unsigned total) {
UMSKT::reportProgress(phase, current, total);
}
void UMSKT::suspendProgressLine(void) {
if (g_progress_fn && !g_progress_suspended) {
g_progress_fn(UMSKT_PROGRESS_BREAK, 0, 0, g_progress_user);
g_progress_suspended = 1;
}
}
void UMSKT::reportProgress(int phase, unsigned current, unsigned total) {
if (g_progress_fn) {
g_progress_suspended = 0;
g_progress_fn(phase, current, total, g_progress_user);
}
}
#ifdef UMSKT_FREESTANDING
#include "../windows/win32_min.h"
@@ -38,6 +101,7 @@ void UMSKT::debugf(const char *fmt, ...) {
if (!debug_on || !fmt) {
return;
}
suspendProgressLine();
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
@@ -61,6 +125,7 @@ void UMSKT::debugf(const char *fmt, ...) {
if (!debug || !fmt) {
return;
}
suspendProgressLine();
va_start(ap, fmt);
vfprintf(debug, fmt, ap);
va_end(ap);
+16
View File
@@ -52,12 +52,21 @@
#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24)
#define BITMASK(n) ((1ULL << (n)) - 1)
enum {
UMSKT_PROGRESS_BREAK = 0,
UMSKT_PROGRESS_MUL = 1,
UMSKT_PROGRESS_GEN = 2,
UMSKT_PROGRESS_VERIFY = 3
};
class UMSKT {
public:
class PIDGEN2;
class PIDGEN3;
class ConfigurationID;
typedef void (*ProgressFn)(int phase, unsigned current, unsigned total, void *user);
#ifdef UMSKT_FREESTANDING
static int debug_on;
#else
@@ -65,6 +74,13 @@ public:
#endif
static void setDebug(int on);
static void debugf(const char *fmt, ...);
static void setProgress(ProgressFn fn, void *user);
static void setMulProgress(int on);
static void setEcProgressPhase(int phase);
static void setProgressLabel(const char *label);
static const char *getProgressLabel(void);
static void suspendProgressLine(void);
static void reportProgress(int phase, unsigned current, unsigned total);
// RNG utility functions
static int umskt_rand_bytes(unsigned char *buf, int num);
+26 -8
View File
@@ -128,10 +128,14 @@ bool PIDGEN3::BINK1998::Verify(
EC_POINT *p = EC_POINT_new(eCurve);
// t = sG
UMSKT::setProgressLabel("s*G");
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_VERIFY);
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, numContext);
// P = eK
UMSKT::setProgressLabel("e*K");
EC_POINT_mul(eCurve, p, nullptr, publicKey, e, numContext);
UMSKT::setProgressLabel(NULL);
// P += t
EC_POINT_add(eCurve, p, t, p, numContext);
@@ -202,10 +206,23 @@ void PIDGEN3::BINK1998::Generate(
// attempt adds G instead of multiplying the curve again. About 1 in 512
// signatures fit in 55 bits, and a 386 cannot afford hundreds of multiplications.
EC_POINT *r = EC_POINT_new(eCurve);
unsigned mul_bits;
UMSKT::umskt_bn_rand(c, FIELD_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
mul_bits = (unsigned)BN_num_bits(c);
if (mul_bits == 0) {
mul_bits = 1;
}
UMSKT::setProgressLabel("R=c*G");
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_MUL);
UMSKT::reportProgress(UMSKT_PROGRESS_MUL, 0, mul_bits);
UMSKT::setMulProgress(1);
EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext);
UMSKT::setMulProgress(0);
UMSKT::setProgressLabel(NULL);
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, 0, 4096u);
do {
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, (unsigned)tries + 1u, 4096u);
// x = R.x; y = R.y;
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
@@ -262,18 +279,19 @@ void PIDGEN3::BINK1998::Generate(
pSignature = 0;
BN_bn2lebinpad(s, (BYTE *)&pSignature, (int)sizeof(pSignature));
tries++;
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, (unsigned)tries, 4096u);
// Pack product key.
Pack(pRaw, pUpgrade, pSerial, pHash, pSignature);
UMSKT::debugf("Generation results:\n");
UMSKT::debugf(" Upgrade: 0x%08x\n", (unsigned)pUpgrade);
UMSKT::debugf(" Serial: 0x%08x\n", (unsigned)pSerial);
UMSKT::debugf(" Hash: 0x%08x\n", (unsigned)pHash);
UMSKT::debugf(" Signature: 0x%08llx\n", (unsigned long long)pSignature);
UMSKT::debugf("\n");
if (tries < 4096 && pSignature > BITMASK(55)) {
if (!(tries < 4096 && pSignature > BITMASK(55))) {
UMSKT::debugf("Generation results:\n");
UMSKT::debugf(" Upgrade: 0x%08x\n", (unsigned)pUpgrade);
UMSKT::debugf(" Serial: 0x%08x\n", (unsigned)pSerial);
UMSKT::debugf(" Hash: 0x%08x\n", (unsigned)pHash);
UMSKT::debugf(" Signature: 0x%08llx\n", (unsigned long long)pSignature);
UMSKT::debugf("\n");
} else {
EC_POINT_add(eCurve, r, r, basePoint, numContext);
BN_add_word(c, 1);
}
+30 -10
View File
@@ -151,16 +151,21 @@ bool PIDGEN3::BINK2002::Verify(
EC_POINT *t = EC_POINT_new(eCurve);
// t = sG
UMSKT::setProgressLabel("s*G");
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_VERIFY);
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, context);
// p = eK
UMSKT::setProgressLabel("e*K");
EC_POINT_mul(eCurve, p, nullptr, publicKey, e, context);
// p += t
EC_POINT_add(eCurve, p, t, p, context);
// p *= s
UMSKT::setProgressLabel("s*P");
EC_POINT_mul(eCurve, p, nullptr, p, s, context);
UMSKT::setProgressLabel(NULL);
// x = p.x; y = p.y;
EC_POINT_get_affine_coordinates(eCurve, p, x, y, context);
@@ -245,10 +250,23 @@ void PIDGEN3::BINK2002::Generate(
// One random scalar. Further candidates are c+1, c+2, ... so each extra
// attempt adds G instead of multiplying the curve again.
EC_POINT *r = EC_POINT_new(eCurve);
unsigned mul_bits;
UMSKT::umskt_bn_rand(c, FIELD_BITS_2003, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
mul_bits = (unsigned)BN_num_bits(c);
if (mul_bits == 0) {
mul_bits = 1;
}
UMSKT::setProgressLabel("R=c*G");
UMSKT::setEcProgressPhase(UMSKT_PROGRESS_MUL);
UMSKT::reportProgress(UMSKT_PROGRESS_MUL, 0, mul_bits);
UMSKT::setMulProgress(1);
EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext);
UMSKT::setMulProgress(0);
UMSKT::setProgressLabel(NULL);
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, 0, 4096u);
do {
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, (unsigned)tries + 1u, 4096u);
// x = R.x; y = R.y;
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
@@ -280,6 +298,7 @@ void PIDGEN3::BINK2002::Generate(
if (!serialInRange) {
noSquare = true;
tries++;
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, (unsigned)tries, 4096u);
if (tries < 4096) {
EC_POINT_add(eCurve, r, r, basePoint, numContext);
BN_add_word(c, 1);
@@ -383,20 +402,21 @@ void PIDGEN3::BINK2002::Generate(
pSignature = 0;
BN_bn2lebinpad(s, (BYTE *)&pSignature, (int)sizeof(pSignature));
tries++;
UMSKT::reportProgress(UMSKT_PROGRESS_GEN, (unsigned)tries, 4096u);
// Pack product key.
Pack(pRaw, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
UMSKT::debugf("Generation results:\n");
UMSKT::debugf(" Upgrade: 0x%08x\n", (unsigned)pUpgrade);
UMSKT::debugf("Channel ID: 0x%08x\n", (unsigned)pChannelID);
UMSKT::debugf(" Hash: 0x%08x\n", (unsigned)pHash);
UMSKT::debugf(" Signature: 0x%08llx\n", (unsigned long long)pSignature);
UMSKT::debugf(" AuthInfo: 0x%08x\n", (unsigned)pAuthInfo);
UMSKT::debugf(" Serial: %06u\n", (unsigned)serial);
UMSKT::debugf("\n");
if (tries < 4096 && (pSignature > BITMASK(62) || noSquare || !serialInRange)) {
if (!(tries < 4096 && (pSignature > BITMASK(62) || noSquare || !serialInRange))) {
UMSKT::debugf("Generation results:\n");
UMSKT::debugf(" Upgrade: 0x%08x\n", (unsigned)pUpgrade);
UMSKT::debugf("Channel ID: 0x%08x\n", (unsigned)pChannelID);
UMSKT::debugf(" Hash: 0x%08x\n", (unsigned)pHash);
UMSKT::debugf(" Signature: 0x%08llx\n", (unsigned long long)pSignature);
UMSKT::debugf(" AuthInfo: 0x%08x\n", (unsigned)pAuthInfo);
UMSKT::debugf(" Serial: %06u\n", (unsigned)serial);
UMSKT::debugf("\n");
} else {
EC_POINT_add(eCurve, r, r, basePoint, numContext);
BN_add_word(c, 1);
}
+3
View File
@@ -15,6 +15,8 @@
extern int main(int argc, char **argv);
extern "C" void umskt_bn_dispatch_init(void);
typedef void (*umskt_ctor)(void);
extern "C" umskt_ctor __init_array_start[] __attribute__((weak));
@@ -680,6 +682,7 @@ extern "C" void mainCRTStartup(void) {
HANDLE heap = GetProcessHeap();
__main();
umskt_bn_dispatch_init();
if (!command) {
command = (char *)"";
}
+23 -25
View File
@@ -134,34 +134,32 @@ if ($importHits.Count -gt 0) {
Fail "imports outside kernel32, or APIs missing on Windows 98 / NT 4: $shown"
}
if ($Arch -eq "x86") {
$badMnemonic = "(?i)^(cmov[a-z]*|fcmov[a-z]*|emms|nopl|nopw|fcomi|fcomip|fucomi|fucomip|movaps|movups|movapd|movupd|movdqa|movdqu|movss|movhps|movlps|movlhps|movhlps|xorps|xorpd|andps|andpd|orps|orpd|addps|addpd|addss|addsd|subps|subpd|subss|subsd|mulps|mulpd|mulss|mulsd|divps|divpd|divss|divsd|cvtsi2ss|cvtsi2sd|cvttss2si|cvttsd2si|cvtss2si|cvtsd2si|pshufd|pshuflw|pshufhw|pshufw|punpck[a-z]+|packss[a-z]+|packus[a-z]+|pcmp[a-z]+|padd[bwdq]|psub[bwdq]|pmullw|pmulhw|pmulhuw|pmaddwd|pavgb|pavgw|pextrw|pinsrw|pmovmskb|prefetch[a-z]*|sfence|mfence|lfence|maskmovq|movntq|movntps|lddqu|pause)\b"
$badRegister = "(?i)%(mm|xmm|ymm|zmm)[0-9]"
$insnHits = New-Object System.Collections.Generic.List[string]
$disasm = & $Objdump -d -M att -- $Exe 2>&1
if ($LASTEXITCODE -ne 0) {
Fail "objdump -d failed"
$badMnemonic = "(?i)^(vfmadd132pd|vfmadd213pd|vfmadd231pd|v4fmadd|v4fnmadd|vp4dpw|vpopcntd|vpopcntq|vbroadcasti32x|vbroadcasti64x|vbroadcastf32x|vbroadcastf64x|vinserti32x|vinserti64x|vextracti32x|vextracti64x|vpermi2|vpermt2|vpcompress|vpexpand|vpgather[dq][dq]|vpscatter|vgatherpf|vscatterpf)\b"
$badRegister = "(?i)%zmm[0-9]"
$insnHits = New-Object System.Collections.Generic.List[string]
$disasm = & $Objdump -d -M att -- $Exe 2>&1
if ($LASTEXITCODE -ne 0) {
Fail "objdump -d failed"
}
foreach ($line in $disasm) {
$text = [string]$line
$insn = $null
if ($text.Contains("`t")) {
$parts = $text.Split("`t")
$insn = $parts[$parts.Length - 1].Trim()
}
foreach ($line in $disasm) {
$text = [string]$line
$insn = $null
if ($text.Contains("`t")) {
$parts = $text.Split("`t")
$insn = $parts[$parts.Length - 1].Trim()
}
if (-not $insn) {
continue
}
if ($insn -match $badMnemonic -or $insn -match $badRegister) {
$insnHits.Add($text.Trim())
if ($insnHits.Count -ge 20) {
break
}
if (-not $insn) {
continue
}
if ($insn -match $badMnemonic -or $insn -match $badRegister) {
$insnHits.Add($text.Trim())
if ($insnHits.Count -ge 20) {
break
}
}
if ($insnHits.Count -gt 0) {
Fail ("forbidden instructions:`n" + ($insnHits -join "`n"))
}
}
if ($insnHits.Count -gt 0) {
Fail ("forbidden instructions:`n" + ($insnHits -join "`n"))
}
Write-Host "Windows baseline check passed ($Arch, kernel32 only): $Exe"