From dcc1ec50f8fd00e9d29f4ba2ab8e32bb996d4e52 Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Tue, 24 Feb 2026 15:45:34 +0000 Subject: [PATCH 1/4] bite.ts-41 update t-encrypt --- node/EncryptMessage.js | 26 ++++++++++++--- node/EncryptMessage.mjs | 25 +++++++++++--- node/EncryptMessageNode.mjs | 51 +++++++++++++++++++++++++++++ node/package.json | 24 +++++++------- scripts/run_emscripten_test.sh | 2 +- test/test.js | 2 +- test/test2Keys.js | 2 +- threshold_encryption/CMakeLists.txt | 38 ++++++++++++++++++--- 8 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 node/EncryptMessageNode.mjs diff --git a/node/EncryptMessage.js b/node/EncryptMessage.js index 0d7b11cc..6c5c46a5 100644 --- a/node/EncryptMessage.js +++ b/node/EncryptMessage.js @@ -1,7 +1,25 @@ -const ModuleFactory = require('./encrypt.js'); +const path = require('path'); +const ModuleFactory = require('./encrypt_node.js'); + +let ModulePromise = null; + +function getModule() { + if (!ModulePromise) { + ModulePromise = ModuleFactory({ + locateFile: (filename) => { + // Should return absolute path to encrypt_node.wasm + if (filename.endsWith('.wasm')) { + return path.join(__dirname, 'encrypt_node.wasm'); + } + return path.join(__dirname, filename); + } + }); + } + return ModulePromise; +} async function encryptMessage(txData, publicKey, aadTE = '', aadAES = '') { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessage', // Name of the exported C++ function 'string', // Return type @@ -12,7 +30,7 @@ async function encryptMessage(txData, publicKey, aadTE = '', aadAES = '') { async function encryptMessageDualKey( txData, firstPublicKey, secondPublicKey, aadTE = '', aadAES = '') { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessageDualKey', // Name of the exported C++ function 'string', // Return type @@ -22,7 +40,7 @@ async function encryptMessageDualKey( } async function encryptMessageMockup(txData) { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessageMockup', // Name of the exported C++ function 'string', // Return type diff --git a/node/EncryptMessage.mjs b/node/EncryptMessage.mjs index b723d087..1c9480ce 100644 --- a/node/EncryptMessage.mjs +++ b/node/EncryptMessage.mjs @@ -1,7 +1,24 @@ -import ModuleFactory from './encrypt.js'; +import ModuleFactory from './encrypt_web.js'; + +let ModulePromise = null; + +function getModule() { + if (!ModulePromise) { + const wasmUrl = new URL('encrypt_web.wasm', import.meta.url).href; + ModulePromise = ModuleFactory({ + locateFile: (path) => { + if (path.endsWith('.wasm')) { + return wasmUrl; + } + return path; + } + }); + } + return ModulePromise; +} export async function encryptMessage(txData, publicKey, aadTE = '', aadAES = '') { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessage', // Name of the exported C++ function 'string', // Return type @@ -12,7 +29,7 @@ export async function encryptMessage(txData, publicKey, aadTE = '', aadAES = '') export async function encryptMessageDualKey( txData, firstPublicKey, secondPublicKey, aadTE = '', aadAES = '') { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessageDualKey', // Name of the exported C++ function 'string', // Return type @@ -22,7 +39,7 @@ export async function encryptMessageDualKey( } export async function encryptMessageMockup(txData) { - const Module = await ModuleFactory(); + const Module = await getModule(); return Module.ccall( 'encryptMessageMockup', // Name of the exported C++ function 'string', // Return type diff --git a/node/EncryptMessageNode.mjs b/node/EncryptMessageNode.mjs new file mode 100644 index 00000000..9a6a82d2 --- /dev/null +++ b/node/EncryptMessageNode.mjs @@ -0,0 +1,51 @@ +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +const ModuleFactory = require('./encrypt_node.js'); + +let ModulePromise = null; + +function getModule() { + if (!ModulePromise) { + ModulePromise = ModuleFactory({ + locateFile: (filename) => { + if (filename.endsWith('.wasm')) { + const path = require('path'); + return path.join(path.dirname(new URL(import.meta.url).pathname), 'encrypt_node.wasm'); + } + return filename; + } + }); + } + return ModulePromise; +} + +export async function encryptMessage(txData, publicKey, aadTE = '', aadAES = '') { + const Module = await getModule(); + return Module.ccall( + 'encryptMessage', + 'string', + ['string', 'string', 'string', 'string'], + [txData, publicKey, aadTE, aadAES] + ); +} + +export async function encryptMessageDualKey( + txData, firstPublicKey, secondPublicKey, aadTE = '', aadAES = '') { + const Module = await getModule(); + return Module.ccall( + 'encryptMessageDualKey', + 'string', + ['string', 'string', 'string', 'string', 'string'], + [txData, firstPublicKey, secondPublicKey, aadTE, aadAES] + ); +} + +export async function encryptMessageMockup(txData) { + const Module = await getModule(); + return Module.ccall( + 'encryptMessageMockup', + 'string', + ['string'], + [txData] + ); +} diff --git a/node/package.json b/node/package.json index b5b258c9..528a585a 100644 --- a/node/package.json +++ b/node/package.json @@ -1,6 +1,6 @@ { "name": "@skalenetwork/t-encrypt", - "version": "0.8.0", + "version": "0.9.0", "keywords": [ "SKALE", @@ -11,13 +11,6 @@ "encryption", "wasm" ], - "browser": { - "fs": false, - "os": false, - "path": false, - "crypto": false, - "child_process": false - }, "homepage": "https://github.com/skalenetwork/libBLS", "license": "AGPL-3.0", "author": "SKALE Labs and contributors", @@ -33,14 +26,21 @@ "sideEffects": false, "exports": { ".": { - "import": "./EncryptMessage.mjs", - "require": "./EncryptMessage.js" + "browser": "./EncryptMessage.mjs", + "node": { + "import": "./EncryptMessageNode.mjs", + "require": "./EncryptMessage.js" + }, + "default": "./EncryptMessage.mjs" } }, "files": [ "EncryptMessage.js", "EncryptMessage.mjs", - "encrypt.js", - "encrypt.wasm" + "EncryptMessageNode.mjs", + "encrypt_node.js", + "encrypt_node.wasm", + "encrypt_web.js", + "encrypt_web.wasm" ] } diff --git a/scripts/run_emscripten_test.sh b/scripts/run_emscripten_test.sh index 4c78501e..2fe304e6 100644 --- a/scripts/run_emscripten_test.sh +++ b/scripts/run_emscripten_test.sh @@ -12,7 +12,7 @@ cp "$ROOT_DIR/tools/generate_bls_keys" "$ABS_BUILD_DIR/" cp "$ROOT_DIR/tools/decrypt_message" "$ABS_BUILD_DIR/" cp "$ROOT_DIR/test/test.js" "$ABS_BUILD_DIR/" cp "$ROOT_DIR/test/test2Keys.js" "$ABS_BUILD_DIR/" -cp "$ABS_BUILD_DIR/threshold_encryption/encrypt."* "$ABS_BUILD_DIR/" +cp "$ABS_BUILD_DIR/threshold_encryption/encrypt_node."* "$ABS_BUILD_DIR/" cd "$ABS_BUILD_DIR/" # Number of times to run the test block diff --git a/test/test.js b/test/test.js index d0de71d2..0b7743b6 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,4 @@ -const ModuleFactory = require("./encrypt.js"); +const ModuleFactory = require("./encrypt_node.js"); const BLS_PUBLIC_KEY = process.argv[2]; const TX_DATA = process.argv[3]; diff --git a/test/test2Keys.js b/test/test2Keys.js index 9412aa1d..17e8555a 100644 --- a/test/test2Keys.js +++ b/test/test2Keys.js @@ -1,4 +1,4 @@ -const ModuleFactory = require("./encrypt.js"); +const ModuleFactory = require("./encrypt_node.js"); const FIRST_BLS_PUBLIC_KEY = process.argv[2]; const SECOND_BLS_PUBLIC_KEY = process.argv[3]; diff --git a/threshold_encryption/CMakeLists.txt b/threshold_encryption/CMakeLists.txt index 58d6684b..855ae865 100644 --- a/threshold_encryption/CMakeLists.txt +++ b/threshold_encryption/CMakeLists.txt @@ -144,11 +144,39 @@ if (NOT EMSCRIPTEN) endif() if (EMSCRIPTEN) - add_executable(encrypt ../threshold_encryption/encryptMessage.cpp ../tools/utils.cpp) - set_target_properties(encrypt PROPERTIES LINK_FLAGS "-s EXIT_RUNTIME=1 -s USE_PTHREADS=0 -s MODULARIZE -s ALLOW_MEMORY_GROWTH=1 -s NO_DISABLE_EXCEPTION_CATCHING=1 -s EXPORTED_RUNTIME_METHODS='[\"ccall\"]' -s EXPORTED_FUNCTIONS='[\"_encryptMessage\", \"_encryptMessageDualKey\",\"_encryptMessageMockup\"]' -s ENVIRONMENT='node,web' -s SINGLE_FILE=1") - target_include_directories(encrypt SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${THIRD_PARTY_DIR}) - target_compile_definitions(encrypt PRIVATE MCL=1) - target_link_libraries(encrypt PRIVATE te) + set(ENCRYPT_SOURCES ../threshold_encryption/encryptMessage.cpp ../tools/utils.cpp) + set(ENCRYPT_LINK_FLAGS "-s EXIT_RUNTIME=1 -s USE_PTHREADS=0 -s MODULARIZE -s ALLOW_MEMORY_GROWTH=1 -s NO_DISABLE_EXCEPTION_CATCHING=1 -s EXPORTED_RUNTIME_METHODS='[\"ccall\"]' -s EXPORTED_FUNCTIONS='[\"_encryptMessage\", \"_encryptMessageDualKey\",\"_encryptMessageMockup\"]'") + + # encrypt_node (for Node.js) + add_executable(encrypt_node ${ENCRYPT_SOURCES}) + target_include_directories(encrypt_node SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${THIRD_PARTY_DIR}) + target_compile_definitions(encrypt_node PRIVATE MCL=1) + target_link_libraries(encrypt_node PRIVATE te) + set_target_properties(encrypt_node PROPERTIES + OUTPUT_NAME "encrypt_node" + LINK_FLAGS "${ENCRYPT_LINK_FLAGS} -s ENVIRONMENT='node'" + ) + + # encrypt_web (for Browser/Webpack) + add_executable(encrypt_web ${ENCRYPT_SOURCES}) + target_include_directories(encrypt_web SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${THIRD_PARTY_DIR}) + target_compile_definitions(encrypt_web PRIVATE MCL=1) + target_link_libraries(encrypt_web PRIVATE te) + set_target_properties(encrypt_web PROPERTIES + OUTPUT_NAME "encrypt_web" + LINK_FLAGS "${ENCRYPT_LINK_FLAGS} -s ENVIRONMENT='web'" + ) + + add_custom_command(TARGET encrypt_node POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/encrypt_node.js ${CMAKE_SOURCE_DIR}/node/encrypt_node.js + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/encrypt_node.wasm ${CMAKE_SOURCE_DIR}/node/encrypt_node.wasm + COMMENT "Copying encrypt_node to node package folder" + ) + add_custom_command(TARGET encrypt_web POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/encrypt_web.js ${CMAKE_SOURCE_DIR}/node/encrypt_web.js + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/encrypt_web.wasm ${CMAKE_SOURCE_DIR}/node/encrypt_web.wasm + COMMENT "Copying encrypt_web to node package folder" + ) add_executable(encrypt_message ../test/encryptMessageJS.cpp ../tools/utils.cpp) target_include_directories(encrypt_message SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${THIRD_PARTY_DIR}) From cd2650eb223547baabfd05eb373a23affb9214cd Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Fri, 17 Apr 2026 18:17:13 +0100 Subject: [PATCH 2/4] fix esm support --- threshold_encryption/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/threshold_encryption/CMakeLists.txt b/threshold_encryption/CMakeLists.txt index 855ae865..719640c5 100644 --- a/threshold_encryption/CMakeLists.txt +++ b/threshold_encryption/CMakeLists.txt @@ -157,14 +157,14 @@ if (EMSCRIPTEN) LINK_FLAGS "${ENCRYPT_LINK_FLAGS} -s ENVIRONMENT='node'" ) - # encrypt_web (for Browser/Webpack) + # encrypt_web (for Browser / Vite / Webpack 5 / native ESM consumers) add_executable(encrypt_web ${ENCRYPT_SOURCES}) target_include_directories(encrypt_web SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${THIRD_PARTY_DIR}) target_compile_definitions(encrypt_web PRIVATE MCL=1) target_link_libraries(encrypt_web PRIVATE te) set_target_properties(encrypt_web PROPERTIES OUTPUT_NAME "encrypt_web" - LINK_FLAGS "${ENCRYPT_LINK_FLAGS} -s ENVIRONMENT='web'" + LINK_FLAGS "${ENCRYPT_LINK_FLAGS} -s ENVIRONMENT='web' -s EXPORT_ES6=1" ) add_custom_command(TARGET encrypt_node POST_BUILD From 993fd2e94090b1c05874070f3353309081dfa10b Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Fri, 24 Apr 2026 15:33:08 +0100 Subject: [PATCH 3/4] fix file path --- node/EncryptMessageNode.mjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/node/EncryptMessageNode.mjs b/node/EncryptMessageNode.mjs index 9a6a82d2..53b0dce9 100644 --- a/node/EncryptMessageNode.mjs +++ b/node/EncryptMessageNode.mjs @@ -1,4 +1,5 @@ import { createRequire } from 'module'; +import { fileURLToPath } from 'url'; const require = createRequire(import.meta.url); const ModuleFactory = require('./encrypt_node.js'); @@ -8,11 +9,10 @@ function getModule() { if (!ModulePromise) { ModulePromise = ModuleFactory({ locateFile: (filename) => { - if (filename.endsWith('.wasm')) { - const path = require('path'); - return path.join(path.dirname(new URL(import.meta.url).pathname), 'encrypt_node.wasm'); - } - return filename; + const resolvedUrl = new URL(filename, import.meta.url); + return resolvedUrl.protocol === 'file:' + ? fileURLToPath(resolvedUrl) + : resolvedUrl.href; } }); } From f584e279a353d48591f32d70c873608ecc2a8402 Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Mon, 27 Apr 2026 11:17:55 +0100 Subject: [PATCH 4/4] update workers env --- node/EncryptMessage.mjs | 104 +++++++++++++++++++++++++++++++++--- node/EncryptMessageNode.mjs | 17 +++--- 2 files changed, 108 insertions(+), 13 deletions(-) diff --git a/node/EncryptMessage.mjs b/node/EncryptMessage.mjs index 1c9480ce..0a4b2f11 100644 --- a/node/EncryptMessage.mjs +++ b/node/EncryptMessage.mjs @@ -1,18 +1,108 @@ import ModuleFactory from './encrypt_web.js'; +import wasmAsset from './encrypt_web.wasm'; let ModulePromise = null; +function getRuntimeBaseUrl() { + if (typeof self !== 'undefined' && self.location && self.location.href) { + return self.location.href; + } + if (typeof document !== 'undefined' && document.baseURI) { + return document.baseURI; + } + return null; +} + +function toAbsoluteAssetUrl(filename) { + if (typeof filename !== 'string' || filename.length === 0) { + throw new TypeError('filename must be a non-empty string'); + } + + const baseUrl = getRuntimeBaseUrl(); + if (!baseUrl) { + return filename; + } + + try { + return new URL(filename, baseUrl).href; + } catch { + return filename; + } +} + +function getWasmModuleCandidate() { + if (typeof WebAssembly === 'undefined' || typeof WebAssembly.Module === 'undefined') { + return null; + } + + if (wasmAsset instanceof WebAssembly.Module) { + return wasmAsset; + } + + if (wasmAsset && wasmAsset.default instanceof WebAssembly.Module) { + return wasmAsset.default; + } + + try { + if (wasmAsset instanceof Uint8Array || wasmAsset instanceof ArrayBuffer) { + return new WebAssembly.Module(wasmAsset); + } + + if (wasmAsset && (wasmAsset.default instanceof Uint8Array || wasmAsset.default instanceof ArrayBuffer)) { + return new WebAssembly.Module(wasmAsset.default); + } + } catch { + // Fall through to URL-based loading below. + } + + return null; +} + +function getWasmUrlCandidate() { + if (typeof wasmAsset === 'string' && wasmAsset.length > 0) { + return wasmAsset; + } + + if (wasmAsset && typeof wasmAsset.default === 'string' && wasmAsset.default.length > 0) { + return wasmAsset.default; + } + + if (wasmAsset && typeof wasmAsset.href === 'string' && wasmAsset.href.length > 0) { + return wasmAsset.href; + } + + return null; +} + function getModule() { if (!ModulePromise) { - const wasmUrl = new URL('encrypt_web.wasm', import.meta.url).href; - ModulePromise = ModuleFactory({ - locateFile: (path) => { - if (path.endsWith('.wasm')) { + const moduleOptions = {}; + const wasmModule = getWasmModuleCandidate(); + const wasmUrl = getWasmUrlCandidate(); + + if (wasmModule) { + moduleOptions.instantiateWasm = (imports, receiveInstance) => { + const instance = new WebAssembly.Instance(wasmModule, imports); + receiveInstance(instance, wasmModule); + return instance.exports; + }; + } + + if (wasmUrl) { + moduleOptions.locateFile = (filename) => { + if (filename.endsWith('.wasm')) { return wasmUrl; } - return path; - } - }); + + return toAbsoluteAssetUrl(filename); + }; + } else { + moduleOptions.locateFile = (filename) => { + return toAbsoluteAssetUrl(filename); + }; + } + + ModulePromise = ModuleFactory(moduleOptions); } return ModulePromise; } diff --git a/node/EncryptMessageNode.mjs b/node/EncryptMessageNode.mjs index 53b0dce9..ed4bad46 100644 --- a/node/EncryptMessageNode.mjs +++ b/node/EncryptMessageNode.mjs @@ -2,17 +2,22 @@ import { createRequire } from 'module'; import { fileURLToPath } from 'url'; const require = createRequire(import.meta.url); const ModuleFactory = require('./encrypt_node.js'); - let ModulePromise = null; - +function resolveModuleAssetPath(filename) { + if (typeof filename !== 'string' || filename.length === 0) { + throw new TypeError('filename must be a non-empty string'); + } + const resolvedPath = fileURLToPath(new URL(filename, import.meta.url)); + if (typeof resolvedPath !== 'string' || resolvedPath.length === 0) { + throw new Error('Failed to resolve module asset path'); + } + return resolvedPath; +} function getModule() { if (!ModulePromise) { ModulePromise = ModuleFactory({ locateFile: (filename) => { - const resolvedUrl = new URL(filename, import.meta.url); - return resolvedUrl.protocol === 'file:' - ? fileURLToPath(resolvedUrl) - : resolvedUrl.href; + return resolveModuleAssetPath(filename); } }); }