GMSSL is a popular library for china national shangmi(SM) algorithms, include sm2, sm3, sm4 and related. But do not have a good implements of Javascript language. also there was another robust library for Shangmi, but it was not used in finance yet. after few days working, today i gonna show you how to use EMScripten to compile it and use it in javascript within browser.
requirements
Install EMScripten and Compile GMSSL
sudo apt install emscripten llvm clang
git clone https://github.com/guanzhi/GmSSL
cd GmSSL && mkdir build
cd build
emcmake cmake ..
emmake make -j8
when you finished the compile process. you will get a lot of wasm file and js file. but it can not work correctly yet.

and you have a static library was named libgmssl.a now.
write c code and compile to WASM with gmssl lib(libgmssl.a)
you should write your own code and compile it with libgmssl.a
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
char* run_test_sm3(const char *test_data) {
return test_sm3(test_data);
}
EMSCRIPTEN_KEEPALIVE
SM2Keys* run_test_sm2_keys(void) {
return generate_sm2_keys();
}
EMSCRIPTEN_KEEPALIVE
char* run_test_sm2_encrypt(const char* public_key_hex, const char* plaintext) {
return test_sm2_encrypt(public_key_hex, plaintext);
}
EMSCRIPTEN_KEEPALIVE
char* run_test_sm2_decrypt(const char* private_key_hex, const char* ciphertext) {
return test_sm2_decrypt(private_key_hex, ciphertext);
}
EMSCRIPTEN_KEEPALIVE
char* run_test_sm2_sign(const char* private_key_hex, const char* message){
return test_sm2_sign(private_key_hex, message);
}
EMSCRIPTEN_KEEPALIVE
int run_test_sm2_verify(const char* public_key_hex, const char* message, const char* signature_hex){
return test_sm2_verify(public_key_hex, message, signature_hex);
}
#endif
those code was demonstrated how to keep your c code can be calling in the Javascript. Once you compiled those c code, you will get a wasm file and js file.
use below shell script to compile it
echo "【Clearing】Remove old complied files....."
rm sm.html sm.js sm.wasm
echo "【Start】Start to building....."
static_gmssllib_path=$PWD/libgmssl.a
source_code=smtest.c
emcc -I/usr/local/include $static_gmssllib_path $source_code \
-s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap","UTF8ToString", "stringToUTF8", "getValue"]' \
-o sm.html
echo "【Done】Build complete"
if you need to return value from c function, you must export runtime function : UTF8ToString
you will get three files :

call it from javascript
<html>
<head>
<script src="sm.js"></script>
<script>
function stringToHex(str) {
let hex = '';
for (let i = 0; i < str.length; i++) {
hex += str.charCodeAt(i).toString(16).padStart(2, '0');
}
return hex;
}
function hexToString(hex) {
// Ensure the hex string length is even
if (hex.length % 2 !== 0) {
throw new Error("Invalid hex string");
}
let str = '';
for (let i = 0; i < hex.length; i += 2) {
// Parse each pair of hex digits as an integer, then convert to a character
const byte = parseInt(hex.substr(i, 2), 16);
str += String.fromCharCode(byte);
}
return str;
}
setTimeout(() => {
const run_test_sm3 = Module.cwrap('run_test_sm3', 'string', ['string']);
// Call the wrapped function
// const hexString = '74657374'; // 'test' in hex
const result = run_test_sm3(stringToHex('test'));
// Output the result
console.log("SM3 Hash:", result);
const run_generate_sm2_keys = Module.cwrap('run_test_sm2_keys', 'number', []);
const keysPtr = run_generate_sm2_keys();
const privateKeyPtr = Module.getValue(keysPtr, 'i32');
const publicKeyPtr = Module.getValue(keysPtr + 4, 'i32');
const privateKey = Module.UTF8ToString(privateKeyPtr);
const publicKey = Module.UTF8ToString(publicKeyPtr);
console.log("Private Key:", privateKey);
console.log("Public Key:", publicKey);
const run_sm2_encrypt = Module.cwrap('run_test_sm2_encrypt', 'string', ['string', 'string']);
const run_sm2_decrypt = Module.cwrap('run_test_sm2_decrypt', 'string', ['string', 'string']);
const run_sm2_sign = Module.cwrap('run_test_sm2_sign', 'string', ['string', 'string']);
const run_sm2_verify = Module.cwrap('run_test_sm2_verify', 'int', ['string', 'string', 'string']);
var plaintext = "This is funny";
try {
var ciphertextHex = run_sm2_encrypt(publicKey, plaintext);
console.log("Ciphertext (hex):", ciphertextHex);
var dec_cipher = run_sm2_decrypt(privateKey, ciphertextHex);
console.log("Plaintext:", dec_cipher);
// pass param to function to c with stringToHex
var signature = run_sm2_sign(privateKey, stringToHex(plaintext));
console.log("Plaintext signature:", signature);
var verify_result = run_sm2_verify(publicKey, stringToHex(plaintext), signature);
if (verify_result == 1) {
console.log("Signature Verify: passed",);
} else {
console.log("Signature Verify: failed",);
}
} catch (e) {
console.error("An error occurred:", e);
}
}, 1000);
</script>
</head>
</html>
and run python -m http.server to host the html, then you will see:

all exported function can be called by wasm with Module.cwrap('run_test_sm2_keys', 'number', []); and
Troubleshooting
- RuntimeError: Aborted(Assertion failed: native function
run_test_sm3 called before runtime initialization)
setTimeout(()=>{
Module._run_test_sm3('test');
}, 1000);
- xxx function was not exported
change your function in the below function list
-s EXPORTED_FUNCTIONS='["_run_test_sm3", "_hex_to_bytes", "_sm3_init", "_sm3_update", "_sm3_finish"]'
- if you need return a value in c but can not accept it in js
just export runtime function: UTF8ToString
EXPORTED_RUNTIME_METHODS='["ccall", "cwrap","UTF8ToString", "stringToUTF8", "getValue"]'
-
if memroy error with Module._xxx
Just replace it with Module.cwrap('run_test_sm2_keys', 'number', []);
-
compare two hash was equal in sign function and verify function
gmssl was accept hex value by default.
Resources
GMSSL is a popular library for china national
shangmi(SM)algorithms, includesm2,sm3,sm4and related. But do not have a good implements of Javascript language. also there was another robust library for Shangmi, but it was not used in finance yet. after few days working, today i gonna show you how to useEMScriptento compile it and use it in javascript within browser.requirements
Install EMScripten and Compile GMSSL
when you finished the compile process. you will get a lot of wasm file and js file. but it can not work correctly yet.

and you have a static library was named
libgmssl.anow.write c code and compile to WASM with gmssl lib(libgmssl.a)
you should write your own code and compile it with
libgmssl.athose code was demonstrated how to keep your c code can be calling in the Javascript. Once you compiled those c code, you will get a
wasmfile andjsfile.use below shell script to compile it
if you need to return value from c function, you must export runtime function : UTF8ToString
you will get three files :

call it from javascript
and run
python -m http.serverto host the html, then you will see:all exported function can be called by wasm with
Module.cwrap('run_test_sm2_keys', 'number', []);andTroubleshooting
run_test_sm3called before runtime initialization)change your function in the below function list
-s EXPORTED_FUNCTIONS='["_run_test_sm3", "_hex_to_bytes", "_sm3_init", "_sm3_update", "_sm3_finish"]'just export runtime function:
UTF8ToStringEXPORTED_RUNTIME_METHODS='["ccall", "cwrap","UTF8ToString", "stringToUTF8", "getValue"]'if memroy error with
Module._xxxJust replace it with
Module.cwrap('run_test_sm2_keys', 'number', []);compare two hash was equal in sign function and verify function
gmssl was accept hex value by default.
Resources