liboqs icon indicating copy to clipboard operation
liboqs copied to clipboard

WASM compatibillity

Open tpbraun96 opened this issue 2 years ago • 29 comments

Ideally, this project should be compilable via emscripten to WASM. Adding compatibility and documentation to make this possible should exist.

tpbraun96 avatar Apr 06 '22 16:04 tpbraun96

We haven't tried this before and don't have experience with WASM. Is this something you've tried? If you have specific CMakeFile changes that have to be made to make it work, feel free to submit that as a pull request.

dstebila avatar Apr 08 '22 15:04 dstebila

I'm going to leave this here for now that way I can look into making liboqs compatible with WASM: https://stackoverflow.com/questions/70311540/compiling-c-with-external-library-to-wasm-using-wasmer

tbraun96 avatar Apr 14 '22 16:04 tbraun96

If you'd like us to look into this, please point to information how to install all required tooling for this sample build script to work? Are there docker images containing such tooling? A quick install on my local machine yields

$ wasimake cmake -GNinja ..
-- The C compiler identification is Clang 9.0.0
-- The ASM compiler identification is unknown
-- Found assembler: /home/mib/.local/bin/wasicc
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /home/mib/.local/bin/wasicc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Warning: Did not find file Compiler/-ASM
CMake Error at CMakeLists.txt:82 (message):
  Unknown or unsupported processor: x86.  Override by setting
  OQS_PERMIT_UNSUPPORTED_ARCHITECTURE=ON


-- Configuring incomplete, errors occurred!
See also "/home/mib/git/oqs/liboqs/build/CMakeFiles/CMakeOutput.log".
See also "/home/mib/git/oqs/liboqs/build/CMakeFiles/CMakeError.log".

--> Where does this reference to "clang-9" come from (I've got 14 installed on the machine)? Why is the architecture reported to be "x86"? It's x86_64:

$ clang --version
Ubuntu clang version 14.0.0-1ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Here's the result of running the "simple" wasienv install script: Pretty unhelpful output...

$ curl https://raw.githubusercontent.com/wasienv/wasienv/master/install.sh | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4788  100  4788    0     0   9516      0 --:--:-- --:--:-- --:--:--  9500

 ┏━━━━━━━━━┓
 ┃         ┃
 ┃   wasi ( env
 ┃         ┃
 ┗━━━━━━━━━┛

> Installing wasienv
WARNING: Skipping wasienv as it is not installed.
Collecting wasienv
  Downloading wasienv-0.5.4.tar.gz (24 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from wasienv) (2.25.1)
Building wheels for collected packages: wasienv
  Building wheel for wasienv (setup.py) ... done
  Created wheel for wasienv: filename=wasienv-0.5.4-py3-none-any.whl size=32525 sha256=2db1b2da3f65e7787f941ec91734b467ce25379e3635af615f7f59c8df25b06f
  Stored in directory: /home/mib/.cache/pip/wheels/da/7b/be/e1738169616e1732950f1e78969da47b36d9343f83057d23ad
Successfully built wasienv
Installing collected packages: wasienv
Successfully installed wasienv-0.5.4
Collecting wasienv
  Using cached wasienv-0.5.4-py3-none-any.whl
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from wasienv) (2.25.1)
Installing collected packages: wasienv
Successfully installed wasienv-0.5.4
> Adding wasienv to bash profile... ✓
sh: 1: /home/mib/.wasienv/bin/wasienv: not found
> wasienv was installed, but doesn't seem to be working :(

baentsch avatar Apr 14 '22 17:04 baentsch

ASM

I notice there is 36% of assembly code in this project. The design goal of WASM is not to handle any hardware vendor-specific native assembly code. Are there any configuration switches to bypass the assembly code and replace it with its C equivalent code (at the expense of performance, most likely)?

If the native assembly code is mandatory, WASM build will be impossible.

DevelopDaily avatar Apr 22 '22 04:04 DevelopDaily

Are there any configuration switches to bypass the assembly code and replace it with its C equivalent code

No, a single such liboqs build option does not exist "out of the box". Arguably, all code/components do exist for most (i.e, the PQClean) algorithms that would allow adding such switch to the cmake build structures in the project, though.

You could get very far already using the build option combination OQS_DIST_BUILD=OFF OQS_OPT_TARGET=generic OQS_USE_OPENSSL=OFF as that combination should disable including all optimization code parts (i.e., assembly code).

So, please give the above a try, feel free to do a PR if you need this or provide us with information why we should spend work cycles on this: I personally have doubts anyone would want to use slow-running cryptography... If you know of concrete use case(s), please let us know.

baentsch avatar Apr 22 '22 06:04 baentsch

Thanks to the advice from @baentsch, the oqs WASM build works now. Here is a mini doc.

  1. Install the the Emscripten

  2. Similar to the oqs build process, the WASM build process is prefixed with the Emscripten command as follows:

emcmake cmake -GNinja -DOQS_USE_OPENSSL=OFF -DOQS_PERMIT_UNSUPPORTED_ARCHITECTURE=ON ..
emmake ninja
  1. Done. It is that simple.

By the way, wasmer should work too if you use the above -D switches.

The oqs source code seems structured very well. It has a "generic" target. Its assembly code does not prevent those pure C code from working. Its runtime fails graciously when the build target is not compiled to fulfill a task, most likely because the target like WASM cannot accept assembly code. For example, instead of crashing, it would print out something like this: KEM algorithm BIKE-L1 not enabled!

Keep up with the great work. Thanks.

Just a friendly reminder. I hope you keep in mind that WASM, representing the web, should be considered a legitimate target. If it is considered "generic", that is fine, as long as it contains only pure (free from assembly code, inline or not) C/C++ code that is not contaminated by the vendor-dependent features such as Linux/Windows system calls.

DevelopDaily avatar Apr 24 '22 23:04 DevelopDaily

I hope you keep in mind that WASM, representing the web, should be considered a legitimate target.

Valid point. Three questions to this: a) Would it be OK we add reference to the above as a section to https://github.com/open-quantum-safe/liboqs/wiki/Platform-specific-notes-for-building-liboqs ? b) Would you consider contributing a WASM-ready demo environment/docker image (at https://github.com/open-quantum-safe/oqs-demos)? c) Would you consider contributing to https://github.com/open-quantum-safe/profiling, adding comparative (performance) tests between classic and QS-crypto using WASM (e.g. comparing to WebCrypto)? I personally still have doubts WASM-compiled crypto code can be useful if too slow... But then again, signature operations are not necessarily performance-sensitive (unlike heavy-duty stream ciphers or KEXs).

baentsch avatar Apr 25 '22 06:04 baentsch

@DevelopDaily When trying out your steps above, the following error appears:

$ emmake ninja
[1/1104] Building C object src/CMakeFiles/oqs.dir/kem/kem.c.o
FAILED: src/CMakeFiles/oqs.dir/kem/kem.c.o 
/emsdk/upstream/emscripten/emcc  -Iinclude -I../src -fPIC -fvisibility=hidden   -Werror -Wall -Wextra -Wpedantic -Wno-unused-command-line-argument -O3 -fomit-frame-pointer -std=gnu11 -MD -MT src/CMakeFiles/oqs.dir/kem/kem.c.o -MF src/CMakeFiles/oqs.dir/kem/kem.c.o.d -o src/CMakeFiles/oqs.dir/kem/kem.c.o   -c ../src/kem/kem.c
../src/kem/kem.c:87:30: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
OQS_API int OQS_KEM_alg_count() {
                             ^
                              void

... lots of the same repeating...

Any idea what's going on here?

To reproduce: docker run -it ubuntu and in it

apt update && apt upgrade -y && apt install -y cmake git ninja-build python3
git clone https://github.com/emscripten-core/emsdk.git && cd emsdk && ./emsdk install latest && ./emsdk activate latest && source ./emsdk_env.sh
git clone https://github.com/open-quantum-safe/liboqs.git && cd liboqs && mkdir build && cd build && emcmake cmake -GNinja -DOQS_USE_OPENSSL=OFF -DOQS_PERMIT_UNSUPPORTED_ARCHITECTURE=ON .. && ninja

baentsch avatar Apr 25 '22 07:04 baentsch

@baentsch

a) Would it be OK we add reference to ... b) Would you consider contributing a WASM-ready demo ... c) Would you consider contributing to ...

Yes for a) For b) and c), I can try...

DevelopDaily avatar Apr 26 '22 03:04 DevelopDaily

@baentsch I only tried the procedure on a full-blown Ubuntu 20.04 Desktop and it worked perfectly.

I will try to do it in a docker container and let you know my testing results.

DevelopDaily avatar Apr 26 '22 03:04 DevelopDaily

@baentsch I only tried the procedure on a full-blown Ubuntu 20.04 Desktop and it worked perfectly.

I will try to do it in a docker container and let you know my testing results.

Thanks. I also tried on a desktop (VM) but got the same error messages. If you simply run the commands above the error message is output straight away. What really is surprising is that the pretty strange error message "a function declaration without a prototype is deprecated in all versions of C" is output: This simply cannot be the case as liboqs is built with many different versions of C compilers -- and none of them (bar this /emsdk/upstream/bin/clang) complains about this... I'd have the impression it doesn't find the header files, but -Iinclude is present on the compiler invocation... Will wait to hear from you before adding the instructions to the "Platform build" wiki.

baentsch avatar Apr 26 '22 10:04 baentsch

@baentsch

../src/kem/kem.c:87:30: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
OQS_API int OQS_KEM_alg_count() {
                             ^
                              void

Actually, that is a legitimate error in the oqs source code.

In the header file kem.h:

OQS_API int OQS_KEM_alg_count(void);

In the kem.c:

OQS_API int OQS_KEM_alg_count()

The void matters to the cutting-edge C compilers such as clang, which thinks the function in the kem.h does not have an implementation and the one in the kem.c is "a function declaration without a prototype." It is easy to fix the problem by just adding the void to the function in the kem.c. That being said, I guess it would take you some time to fix all the missing void errors.

The WASM build succeeded on my local machine because it used a slightly older compiler, which does not enforce the function prototype. The docker image always uses the latest compiler, which is supposed to fail the build.

DevelopDaily avatar Apr 27 '22 06:04 DevelopDaily

Thanks for the analysis, @DevelopDaily !

baentsch avatar Apr 27 '22 06:04 baentsch

After the issue #1204 is resolved, you may build a local docker image to build the WASM. I use Ubuntu. I've made a very simple Dockerfile

FROM emscripten/emsdk:latest 
RUN apt -y update
RUN apt -y install astyle cmake gcc ninja-build libssl-dev python3-pytest python3-pytest-xdist unzip xsltproc doxygen graphviz python3-yaml
RUN git clone https://github.com/open-quantum-safe/liboqs.git 

Here is the procedure.

  1. Create a directory that contains only the Dockerfile
  2. Go to that directory to build a local docker image named oqs_wasm: sudo docker build -t oqs_wasm .
  3. Run that image: sudo docker run -it oqs_wasm
  4. Now, you have a fully configured WASM build environment running in a ubuntu container. The oqs resides under /src/liboqs
  5. So, create the build directory under that:
cd /src/liboqs/
mkdir build && cd build
  1. Now, you are under /src/liboqs/build
  2. Similar to the oqs build process, the WASM build process is prefixed with the Emscripten command as follows:
emcmake cmake -GNinja -DOQS_USE_OPENSSL=OFF -DOQS_PERMIT_UNSUPPORTED_ARCHITECTURE=ON ..
emmake ninja
  1. Done

DevelopDaily avatar Apr 28 '22 02:04 DevelopDaily

Thanks for the walk-through, @DevelopDaily . Based on this, it should be possible to build a fully working WASM environment in the above even before #1204 is resolved by simply removing one line: https://github.com/open-quantum-safe/liboqs/blob/9dea0430ed764af2f0728793e783f04e5c0cd32d/.CMake/compiler_opts.cmake#L68

baentsch avatar Apr 28 '22 04:04 baentsch

@baentsch You are correct.

After removing that line, I just built the WASM in the container successfully.

You may polish the image however you see fit. That pretty much fulfills your earlier request:

b) Would you consider contributing a WASM-ready demo ...

If necessary, I may add a a little description later for the demo. Basically, all the out-of-the-box oqs tests under /src/liboqs/build/tests should work automatically, albeit with reduced capabilities because of the skipped assembly code.

For example, you can create a test file whatever_to_be_hashed.txt. Then, run

node test_hash.js sha256 < whatever_to_be_hashed.txt

You should see the hash of that file.

DevelopDaily avatar Apr 28 '22 05:04 DevelopDaily

Thanks for the confirmation, @DevelopDaily ! As I have 0 knowledge of WASM, (where) are there specific crypto tests (beyond hashing as per your suggestion) that we could run/trigger QSC? Or is it as simple as running "our" speed_kem etc. tests? Do they become "WASM executables" or is there a JS-wrapper required to trigger them?

baentsch avatar Apr 28 '22 05:04 baentsch

@baentsch Precisely, it is as simple as running "your" existing tests. There are JS-wrappers to trigger them. A "WASM executable" is composed of two files. Take the speed_kem as an example, they are speed_kem.js and speed_kem.wasm. You run it like this:

node speed_kem.js

Under the hood, the speed_kem.js is going to deal with the speed_kem.wasm. The beauty is that the WASM build process uses "your" existing scripts, without any modification, to take care of everything to produce the "WASM executables".

DevelopDaily avatar Apr 28 '22 05:04 DevelopDaily

@baentsch This may help visualize how it is run. By the way, some results look unusual. But, that would be a different story worth investigating later.

root@01a2bff21cba:/src/liboqs/build/tests# node speed_kem.js 
Configuration info
==================
Target platform:  x86-Linux-5.4.0-109-generic
Compiler:         clang (15.0.0 (https://github.com/llvm/llvm-project faef447e72a5c63dfb12bb7b02d44c3c916d31cd))
Compile options:  [-Werror;-Wall;-Wextra;-Wno-unused-command-line-argument;-O3;-fomit-frame-pointer;-Wbad-function-cast;-Wcast-qual;-Wnarrowing;-Wconversion]
OQS version:      0.7.2-dev
Git commit:       9dea0430ed764af2f0728793e783f04e5c0cd32d (+ local modifications)
OpenSSL enabled:  No
AES:              C
SHA-2:            C
SHA-3:            C
OQS build flags:  OQS_OPT_TARGET=generic CMAKE_BUILD_TYPE=Release 
CPU exts compile-time: 

Speed test
==========
Started at 2022-04-28 05:46:34
Operation                      | Iterations | Total time (s) | Time (us): mean | pop. stdev | High-prec time (ns): mean | pop. stdev
------------------------------ | ----------:| --------------:| ---------------:| ----------:| -------------------------:| ----------:
Classic-McEliece-348864        |            |                |                 |            |                           |           
keygen                         |          4 |          3.049 |      762250.000 | 604095.346 |                 762249984 |  604095356
encaps                         |        880 |          3.001 |        3410.227 |   2851.018 |                   3401136 |    2849925
decaps                         |       4634 |          3.006 |         648.684 |   1153.335 |                    643073 |    1144094
Classic-McEliece-348864f       |            |                |                 |            |                           |           
keygen                         |          7 |          3.747 |      535285.714 | 157769.012 |                 535285723 |  157768967
encaps                         |        774 |          3.000 |        3875.969 |   4339.604 |                   3870801 |    4338862
decaps                         |       6441 |          3.000 |         465.766 |   1038.963 |                    464214 |    1038765
Classic-McEliece-460896        |            |                |                 |            |                           |           
keygen                         |          2 |          3.812 |     1906000.000 | 290000.000 |                1906000000 |  290000000
encaps                         |        453 |          3.004 |        6631.347 |   5063.708 |                   6629140 |    5065509
decaps                         |       2384 |          3.000 |        1258.389 |    840.669 |                   1257550 |     840945
Classic-McEliece-460896f       |            |                |                 |            |                           |           
keygen                         |          3 |          5.592 |     1864000.000 | 582381.891 |                1864000000 |  582381838
encaps                         |        353 |          3.004 |        8509.915 |   8257.920 |                   8507082 |    8259292
decaps                         |       2694 |          3.000 |        1113.586 |    433.919 |                   1110987 |     427271
Classic-McEliece-6688128       |            |                |                 |            |                           |           
keygen                         |          2 |          8.463 |     4231500.000 | 1353500.000 |                4231499904 | 1353500032
encaps                         |        220 |          3.001 |       13640.909 |   8642.030 |                  13640909 |    8642031
decaps                         |       2172 |          3.000 |        1381.215 |    751.412 |                   1379374 |     745581
Classic-McEliece-6688128f      |            |                |                 |            |                           |           
keygen                         |          2 |          4.352 |     2176000.000 | 139000.000 |                2176000000 |  138999808
encaps                         |        333 |          3.003 |        9018.018 |   6791.156 |                   9012012 |    6791174
decaps                         |       2110 |          3.000 |        1421.801 |   2146.815 |                   1418958 |    2143394
Classic-McEliece-6960119       |            |                |                 |            |                           |           
keygen                         |          2 |          4.813 |     2406500.000 | 249500.000 |                2406499968 |  249500032
encaps                         |        435 |          3.006 |        6910.345 |   4507.338 |                   6901150 |    4506638
decaps                         |       2665 |          3.000 |        1125.704 |    565.715 |                   1125328 |     561475
Classic-McEliece-6960119f      |            |                |                 |            |                           |           
keygen                         |          2 |          4.413 |     2206500.000 |  15500.000 |                2206500096 |   15500032
encaps                         |        349 |          3.002 |        8601.719 |   5879.799 |                   8595989 |    5884765
decaps                         |       1974 |          3.000 |        1519.757 |   1639.916 |                   1517730 |    1639635
Classic-McEliece-8192128       |            |                |                 |            |                           |           
keygen                         |          1 |          8.003 |     8003000.000 |      0.000 |                8003000064 |          0
encaps                         |        359 |          3.000 |        8356.546 |   5573.105 |                   8350976 |    5566952
decaps                         |       1607 |          3.001 |        1867.455 |   2100.281 |                   1865588 |    2098830
Classic-McEliece-8192128f      |            |                |                 |            |                           |           
keygen                         |          1 |          3.442 |     3442000.000 |      0.000 |                3442000128 |          0
encaps                         |        469 |          3.002 |        6400.853 |   4390.492 |                   6373134 |    4052869
decaps                         |       2316 |          3.000 |        1295.337 |    710.150 |                   1293178 |     704643
HQC-128                        |            |                |                 |            |                           |           
keygen                         |       2130 |          3.000 |        1408.451 |    810.335 |                   1405164 |     808218
encaps                         |       1828 |          3.000 |        1641.138 |    825.134 |                   1640044 |     822672
decaps                         |       1451 |          3.000 |        2067.540 |    807.179 |                   2066850 |     806809
HQC-192                        |            |                |                 |            |                           |           
keygen                         |       1155 |          3.001 |        2598.268 |   1082.564 |                   2597403 |    1078637
encaps                         |        762 |          3.002 |        3939.633 |   1206.513 |                   3938320 |    1206989
decaps                         |        575 |          3.004 |        5224.348 |   1477.989 |                   5220870 |    1478511
HQC-256                        |            |                |                 |            |                           |           
keygen                         |        869 |          3.000 |        3452.244 |   1277.074 |                   3451093 |    1276135
encaps                         |        461 |          3.000 |        6507.592 |   1413.618 |                   6498915 |    1413638
decaps                         |        340 |          3.001 |        8826.471 |   2130.149 |                   8811765 |    2132347
Kyber512                       |            |                |                 |            |                           |           
keygen                         |       6438 |          3.000 |         465.983 |    791.188 |                    465362 |     788802
encaps                         |       8706 |          3.000 |         344.590 |    650.525 |                    342982 |     646595
decaps                         |      16524 |          3.000 |         181.554 |    468.012 |                    181191 |     467635
Kyber768                       |            |                |                 |            |                           |           
keygen                         |       5664 |          3.000 |         529.661 |    757.614 |                    528778 |     757648
encaps                         |       7003 |          3.000 |         428.388 |    635.568 |                    426674 |     631767
decaps                         |       9763 |          3.000 |         307.283 |    499.939 |                    306770 |     499331
Kyber1024                      |            |                |                 |            |                           |           
keygen                         |       4697 |          3.000 |         638.706 |    777.571 |                    637854 |     777722
encaps                         |       6044 |          3.000 |         496.360 |    683.177 |                    494375 |     677327
decaps                         |       6981 |          3.000 |         429.738 |    576.330 |                    428878 |     576225
Kyber512-90s                   |            |                |                 |            |                           |           
keygen                         |       5609 |          3.001 |         535.033 |    887.842 |                    534676 |     887858
encaps                         |       7561 |          3.000 |         396.773 |    683.828 |                    395450 |     680330
decaps                         |      13968 |          3.000 |         214.777 |    450.251 |                    213774 |     440445
Kyber768-90s                   |            |                |                 |            |                           |           
keygen                         |       4659 |          3.000 |         643.915 |    798.724 |                    641554 |     791589
encaps                         |       5369 |          3.000 |         558.763 |    729.307 |                    556901 |     726899
decaps                         |       7020 |          3.000 |         427.350 |    551.603 |                    426638 |     551509
Kyber1024-90s                  |            |                |                 |            |                           |           
keygen                         |       3627 |          3.000 |         827.130 |    778.929 |                    826854 |     779045
encaps                         |       4523 |          3.000 |         663.277 |    694.276 |                    660845 |     692613
decaps                         |       4883 |          3.000 |         614.376 |    586.361 |                    613352 |     586562
NTRU-HPS-2048-509              |            |                |                 |            |                           |           
keygen                         |         99 |          3.034 |       30646.465 |   5222.935 |                  30646466 |    5222937
encaps                         |        225 |          3.003 |       13346.667 |   3900.405 |                  13342222 |    3902504
decaps                         |       6325 |          3.002 |         474.625 |    560.516 |                    472885 |     556188
NTRU-HPS-2048-677              |            |                |                 |            |                           |           
keygen                         |         85 |          3.011 |       35423.529 |   8228.182 |                  35423530 |    8228180
encaps                         |        203 |          3.002 |       14788.177 |   4131.992 |                  14788178 |    4131985
decaps                         |       3482 |          3.000 |         861.574 |    619.258 |                    860712 |     619761
NTRU-HPS-4096-821              |            |                |                 |            |                           |           
keygen                         |         47 |          3.013 |       64106.383 |   8942.450 |                  64106382 |    8942463
encaps                         |        158 |          3.000 |       18987.342 |   4224.682 |                  18987342 |    4224678
decaps                         |       2995 |          3.000 |        1001.669 |    776.747 |                   1000000 |     773089
NTRU-HPS-4096-1229             |            |                |                 |            |                           |           
keygen                         |         25 |          3.071 |      122840.000 |  14371.305 |                 122840003 |   14371313
encaps                         |        108 |          3.037 |       28120.370 |   5427.498 |                  28120370 |    5427499
decaps                         |       1190 |          3.000 |        2521.008 |    826.542 |                   2521008 |     826544
NTRU-HRSS-701                  |            |                |                 |            |                           |           
keygen                         |         80 |          3.014 |       37675.000 |   7690.538 |                  37662499 |    7684305
encaps                         |        476 |          3.009 |        6321.429 |   2261.210 |                   6313026 |    2256810
decaps                         |       3406 |          3.000 |         880.799 |    528.574 |                    879918 |     528652
NTRU-HRSS-1373                 |            |                |                 |            |                           |           
keygen                         |         22 |          3.132 |      142363.636 |  10364.035 |                 142363625 |   10363997
encaps                         |        213 |          3.009 |       14126.761 |   3115.596 |                  14117370 |    3111448
decaps                         |        829 |          3.001 |        3620.024 |   1070.105 |                   3616406 |    1061448
ntrulpr653                     |            |                |                 |            |                           |           
keygen                         |        248 |          3.004 |       12112.903 |   3244.623 |                  12108870 |    3245391
encaps                         |       1869 |          3.003 | 9869847016432618.000 | 426578396169597376.000 |                   3902604 |   81887207
decaps                         |       1108 |          3.002 |        2709.386 |   1022.501 |                   2705776 |    1023240
ntrulpr761                     |            |                |                 |            |                           |           
keygen                         |        175 |          3.005 |       17171.429 |   4777.840 |                  17171428 |    4777839
encaps                         |       1251 |          3.000 |        2398.082 |   1110.863 |                   2389289 |    1104252
decaps                         |        833 |          3.001 |        3602.641 |   1291.525 |                   3601441 |    1287890
ntrulpr857                     |            |                |                 |            |                           |           
keygen                         |        144 |          3.010 |       20902.778 |   6880.245 |                  20902779 |    6880245
encaps                         |        925 |          3.002 |        3245.405 |    892.790 |                   3244325 |     892480
decaps                         |        781 |          3.003 |        3845.070 |   1091.378 |                   3841229 |    1090240
ntrulpr1277                    |            |                |                 |            |                           |           
keygen                         |        105 |          3.004 |       28609.524 |   6371.806 |                  28609524 |    6371803
encaps                         |        446 |          3.002 |        6730.942 |   1571.690 |                   6724216 |    1572662
decaps                         |        315 |          3.009 |        9552.381 |   2082.341 |                   9549206 |    2082420
sntrup653                      |            |                |                 |            |                           |           
keygen                         |         44 |          3.028 |       68818.182 |  12579.335 |                  68795456 |   12572651
encaps                         |        261 |          3.003 |       11505.747 |   3519.645 |                  11501915 |    3516376
decaps                         |       1459 |          3.000 |        2056.203 |    824.318 |                   2054147 |     823215
sntrup761                      |            |                |                 |            |                           |           
keygen                         |         38 |          3.070 |       80789.474 |  10283.246 |                  80789477 |   10283229
encaps                         |        193 |          3.001 |       15549.223 |   3499.654 |                  15544041 |    3504164
decaps                         |        905 |          3.001 |        3316.022 |    818.041 |                   3312707 |     817291
sntrup857                      |            |                |                 |            |                           |           
keygen                         |         29 |          3.054 |      105310.345 |  11086.193 |                 105310349 |   11086207
encaps                         |        207 |          3.008 |       14531.401 |   3994.892 |                  14526570 |    3999761
decaps                         |        748 |          3.004 |        4016.043 |   1063.371 |                   4012032 |    1064050
sntrup1277                     |            |                |                 |            |                           |           
keygen                         |         14 |          3.046 |      217571.429 |  37419.846 |                 217571438 |   37419880
encaps                         |         76 |          3.037 |       39960.526 |  20160.175 |                  39960529 |   20160191
decaps                         |        152 |          3.009 |       19796.053 |  10483.282 |                  19782895 |   10464175
LightSaber-KEM                 |            |                |                 |            |                           |           
keygen                         |       3377 |          3.001 |         888.659 |   1653.071 |                    886882 |    1652052
encaps                         |       7826 |          3.000 |         383.338 |    742.282 |                    381293 |     738853
decaps                         |       9503 |          3.000 |         315.690 |    648.534 |                    315269 |     647926
Saber-KEM                      |            |                |                 |            |                           |           
keygen                         |       3197 |          3.000 |         938.380 |   1008.078 |                    937441 |    1007551
encaps                         |       4210 |          3.000 |         712.589 |    856.474 |                    711401 |     853996
decaps                         |       4391 |          3.001 |         683.443 |   1022.853 |                    680938 |    1021298
FireSaber-KEM                  |            |                |                 |            |                           |           
keygen                         |       2635 |          3.000 |        1138.520 |   1359.546 |                   1138140 |    1359728
encaps                         |       3185 |          3.000 |         941.915 |    758.055 |                    940345 |     757730
decaps                         |       3571 |          3.000 |         840.101 |    571.834 |                    838421 |     566441
FrodoKEM-640-AES               |            |                |                 |            |                           |           
keygen                         |        158 |          3.002 |       19000.000 |   3289.800 |                  19000001 |    3289802
encaps                         |        185 |          3.011 |       16275.676 |   3823.781 |                  16270271 |    3795082
decaps                         |        150 |          3.017 |       20113.333 |   3677.928 |                  20113335 |    3677934
FrodoKEM-640-SHAKE             |            |                |                 |            |                           |           
keygen                         |        246 |          3.015 |       12256.098 |   2360.641 |                  12252033 |    2361940
encaps                         |        187 |          3.000 |       16042.781 |   5568.080 |                  16037432 |    5570514
decaps                         |        228 |          3.008 |       13192.982 |   3664.379 |                  13184211 |    3637198
FrodoKEM-976-AES               |            |                |                 |            |                           |           
keygen                         |         79 |          3.008 |       38075.949 |   5950.794 |                  38075949 |    5950788
encaps                         |         70 |          3.020 |       43142.857 |   8690.365 |                  43142857 |    8690355
decaps                         |         72 |          3.013 |       41847.222 |   7398.686 |                  41847221 |    7398679
FrodoKEM-976-SHAKE             |            |                |                 |            |                           |           
keygen                         |        110 |          3.019 |       27445.455 |   4862.821 |                  27427272 |    4845726
encaps                         |        100 |          3.012 |       30120.000 |   6624.621 |                  30120000 |    6624622
decaps                         |         97 |          3.016 |       31092.784 |   4907.563 |                  31082475 |    4906697
FrodoKEM-1344-AES              |            |                |                 |            |                           |           
keygen                         |         39 |          3.005 |       77051.282 |  10265.573 |                  77051280 |   10265575
encaps                         |         38 |          3.080 |       81052.632 |  13258.458 |                  81052632 |   13258458
decaps                         |         39 |          3.053 |       78282.051 |   8808.355 |                  78282050 |    8808360
FrodoKEM-1344-SHAKE            |            |                |                 |            |                           |           
keygen                         |         68 |          3.019 |       44397.059 |   9672.793 |                  44397056 |    9672790
encaps                         |         51 |          3.031 |       59431.373 |   9280.498 |                  59431369 |    9280522
decaps                         |         52 |          3.052 |       58692.308 |   7921.583 |                  58692308 |    7921569
Ended at 2022-04-28 05:53:13

DevelopDaily avatar Apr 28 '22 05:04 DevelopDaily

Thanks for the explanations and test-run, @DevelopDaily ! At first glance this looks like 5-15% of native performance: Is that expected for WASM code? Some papers claim the gap should be smaller. Any idea how to compare this with "classic crypto" used via WASM? e.g., is there a way to compile openssl (3) for WASM? We could then run classic and QS crypto "head-to-head"...

baentsch avatar Apr 28 '22 06:04 baentsch

@baentsch

is there a way to compile openssl (3) for WASM?

Yes, but it is more difficult because openssl is quite an old-school project. I'll see what I can do...

DevelopDaily avatar Apr 29 '22 05:04 DevelopDaily

@baentsch

... compile openssl (3) for WASM? We could then run classic and QS crypto "head-to-head".

I have built the openssl perfectly. Unfortunately, however, I am afraid a "head-to-head" comparison won't be useful because the WASM openssl speed is excruciatingly slow (up to minutes and hours) for three reasons:

  • openssl uses assembly language too. After it is disabled, that presumably makes the system very slow
  • The openssl benchmark program speed itself may contain bugs. They may have manifested themselves spectacularly in WASM runtime.
  • openssl may be very old-fashioned - simply not cut out for a modern runtime like WASM

... this looks like 5-15% of native performance: Is that expected for WASM code? Some papers claim the gap should be smaller.

Performance benchmark is a very complex issue, on which I am not an expert. Here is my understanding. The near-native performance claim of WASM is based on pure C/C++ code, which must be well-written and straightforward enough to give a modern compiler a chance to apply its optimization strategy to produce high quality assembly code. It may never beat hand-crafted assembly code in some occasions, but, in most cases, it should outperform its hand-crafted counterparts. I usually refine my C/C++ as much as possible, unless I have to write assembly, as a last resort.

For pure C/C++, I did some casual benchmarking on this code:

#include <vector>
#include <algorithm>
int main()
{
    std::vector<size_t> v(50000000, 0);
    std::sort(v.begin(), v.end());    
    return 0;
}

Native build and run:

c++ -O3 sort.cpp
time ./a.out

real	0m5.090s
user	0m3.870s
sys	0m0.678s

WASM build and run:

emcc -O3 -s TOTAL_MEMORY=167772160 -s ALLOW_MEMORY_GROWTH=1 sort.cpp
time node a.out.js 

real	0m1.496s
user	0m0.906s
sys	0m0.367s

As you can see, the WASM run is actually much faster.

DevelopDaily avatar May 01 '22 23:05 DevelopDaily

openssl speed is excruciatingly slow

No question, if it runs through all algorithms. What I meant to ask is: What is the relative WASM performance of functionally comparable algorithms, say for signatures, i.e., openssl speed -seconds 5 rsa compared to openssl speed -seconds 5 dilithium3?

openssl uses assembly language too. After it is disabled, that presumably makes the system very slow

If you use the commands above, it should allow you to compare non-assembly crypto implementations (classic vs. QS) with the same testing overhead in both cases.

The openssl benchmark program speed itself may contain bugs.

It might -- but this is highly improbable as this is pretty "seasoned" code as you also point out. It surely has not been written with WASM in mind -- but so did none of the QS algorithms.

As you can see, the WASM run is actually much faster.

Agreed -- but then again this sample basically runs two, probably differently optimized library functions against each other, not real, external code as the two commands suggested above would do.

baentsch avatar May 02 '22 05:05 baentsch

@baentsch

If you use the commands above, it should allow you to compare non-assembly crypto implementations

WASM run:

node openssl speed -seconds 5 rsa
RSA sign setup failure.  No RSA sign will be done.
00000000:error:020C0100:rsa routines:rsa_ossl_private_encrypt:malloc failure:crypto/rsa/rsa_ossl.c:265:
00000000:error:1C880004:Provider routines:rsa_sign:RSA lib:providers/implementations/signature/rsa_sig.c:652:
RSA verify setup failure.  No RSA verify will be done.
version: 3.1.0-dev
built on: Tue May  3 02:42:02 2022 UTC
options: bn(32,32)
compiler: /home/t/emsdk/upstream/emscripten/emcc  -Wall -O3 -DOPENSSL_USE_NODELETE -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -DOPENSSL_SYS_NETWARE -DSIG_DFL=0 -DSIG_IGN=0 -DHAVE_FORK=0 -DNO_SYSLOG
CPUINFO: N/A
node openssl speed -seconds 5 dilithium3
speed: Unknown algorithm dilithium3

Native run:

./openssl speed -seconds 5 rsa
Doing 512 bits private rsa's for 5s: 47362 512 bits private RSA's in 4.92s
Doing 512 bits public rsa's for 5s: 659252 512 bits public RSA's in 4.88s
Doing 1024 bits private rsa's for 5s: 12780 1024 bits private RSA's in 4.91s
Doing 1024 bits public rsa's for 5s: 221195 1024 bits public RSA's in 4.92s
Doing 2048 bits private rsa's for 5s: 2504 2048 bits private RSA's in 4.93s
Doing 2048 bits public rsa's for 5s: 67720 2048 bits public RSA's in 4.95s
Doing 3072 bits private rsa's for 5s: 615 3072 bits private RSA's in 4.92s
Doing 3072 bits public rsa's for 5s: 29578 3072 bits public RSA's in 4.92s
Doing 4096 bits private rsa's for 5s: 271 4096 bits private RSA's in 4.95s
Doing 4096 bits public rsa's for 5s: 17182 4096 bits public RSA's in 4.90s
Doing 7680 bits private rsa's for 5s: 34 7680 bits private RSA's in 4.99s
Doing 7680 bits public rsa's for 5s: 5108 7680 bits public RSA's in 4.95s
Doing 15360 bits private rsa's for 5s: 6 15360 bits private RSA's in 5.49s
Doing 15360 bits public rsa's for 5s: 1295 15360 bits public RSA's in 4.91s
version: 3.1.0-dev
built on: Sun May  1 18:35:59 2022 UTC
options: bn(64,64)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -O3 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG
CPUINFO: OPENSSL_ia32cap=0xdef8220b078bffff:0x21
                  sign    verify    sign/s verify/s
rsa  512 bits 0.000104s 0.000007s   9626.4 135092.6
rsa 1024 bits 0.000384s 0.000022s   2602.9  44958.3
rsa 2048 bits 0.001969s 0.000073s    507.9  13680.8
rsa 3072 bits 0.008000s 0.000166s    125.0   6011.8
rsa 4096 bits 0.018266s 0.000285s     54.7   3506.5
rsa 7680 bits 0.146765s 0.000969s      6.8   1031.9
rsa 15360 bits 0.915000s 0.003792s      1.1    263.7
./openssl speed -seconds 5 dilithium3
speed: Unknown algorithm dilithium3

Both tests failed on the WASM openssl. If you have some other specific commands to run, I can do it. I update the docker file and you can build your own as well.

Dockerfile

FROM emscripten/emsdk:latest 
RUN apt -y update
RUN apt -y install astyle cmake gcc ninja-build libssl-dev python3-pytest python3-pytest-xdist unzip xsltproc doxygen graphviz python3-yaml
RUN git clone https://github.com/open-quantum-safe/liboqs.git 
RUN git clone https://github.com/openssl/openssl.git

In the docker image, follow this procedure to build:

cd /src/liboqs/
mkdir build && cd build
emcmake cmake -GNinja -DOQS_USE_OPENSSL=OFF -DOQS_PERMIT_UNSUPPORTED_ARCHITECTURE=ON ..
emmake ninja
cd /src/openssl/
emconfigure ./Configure linux-generic64 -no-asm -no-threads -static -no-afalgeng -DOPENSSL_SYS_NETWARE -DSIG_DFL=0 -DSIG_IGN=0 -DHAVE_FORK=0 -DNO_SYSLOG
sed -i 's|^CROSS_COMPILE.*$|CROSS_COMPILE=|g' Makefile
emmake make

DevelopDaily avatar May 04 '22 01:05 DevelopDaily

Performance aside, I've created a small demo of using the library in the browser: https://github.com/x0wllaar/liboqs-wasm. I did not test with Node/Bun, but I think it should work there as well.

In general, unmodified library code works, but I had to write some very boilerplate accessor methods, and then write a more idiomatic wrapper in JS.

On the performance side, for me everything I tested except SPHINCS+ worked smoothly enough to not notice it blocking the event loop. For client side, even with SPHINCS+, it can be mitigated by moving it into a worker thread. I did not test McEliece.

PS: Is it possible to enable BIKE in WASM and to add MAYO signatures? Testing BIKE was kind of a half of my inspiration for doing all this and MAYO just seems cool.

x0wllaar avatar May 16 '24 02:05 x0wllaar

Performance aside, I've created a small demo of using the library in the browser: https://github.com/x0wllaar/liboqs-wasm. I did not test with Node/Bun, but I think it should work there as well.

In general, unmodified library code works, but I had to write some very boilerplate accessor methods, and then write a more idiomatic wrapper in JS.

On the performance side, for me everything I tested except SPHINCS+ worked smoothly enough to not notice it blocking the event loop. For client side, even with SPHINCS+, it can be mitigated by moving it into a worker thread. I did not test McEliece.

PS: Is it possible to enable BIKE in WASM and to add MAYO signatures? Testing BIKE was kind of a half of my inspiration for doing all this and MAYO just seems cool.

Thanks, looks interesting.

MAYO is being worked on in #1707 and will hopefully land in liboqs soon. BIKE is already available. We have two BIKE implementation versions -- a generic C for 64-bit little endian, and an x86_64 optimized implementation. I'm not sure how that would interact with the constraints of WASM.

dstebila avatar May 16 '24 07:05 dstebila

64-bit little endian

Yeah that's the problem as by default Emscripten compiles for 32-bit WASM. The 64-bit version is not really supported right now (see https://webassembly.org/features/, specifically Memory64 there).

Emscripten supports (https://emscripten.org/docs/tools_reference/settings_reference.html?highlight=environment#memory64) "faking it" by compiling to 64-bit and then lowering to 32, I'll see if/how well it works for liboqs.

From the JS side, the only change would be to add a way to determine the size of size_t at runtime (currently hardcoded to 4 in the wrapper), and then just make sure that BigInt pointers are interpreted correctly (for null checks etc). Both of these seem very easy to do for me.

I'll try to do it by the end of this week.

Among other things to address is the 16mb stack size, which is kinda necessary for McEliece to work, but I'll see how much I can lower it and still have it working. Is the large stack still required when using heap-allocated versions of KEMs/Signatures?

x0wllaar avatar May 16 '24 16:05 x0wllaar

After some fighting with CMake, I managed to get BIKE to work in browsers without any experimental options, thank you!

x0wllaar avatar May 16 '24 21:05 x0wllaar

After some fighting with CMake, I managed to get BIKE to work in browsers without any experimental options, thank you!

Thanks for letting us know @x0wllaar . If there'd be something you learned that may benefit other users of liboqs please feel free to share, e.g., by PR to the cmake option documentation.

baentsch avatar May 17 '24 05:05 baentsch