Skip to content

Instantly share code, notes, and snippets.

@bergkvist
Last active October 27, 2023 01:51
Show Gist options
  • Save bergkvist/186b15ec2b7e9cb04f7835973ae98371 to your computer and use it in GitHub Desktop.
Save bergkvist/186b15ec2b7e9cb04f7835973ae98371 to your computer and use it in GitHub Desktop.
Fireblocks MPC compiled to wasm32-wasi using zig
# How to use:
# 1. Make sure you have nix installed (https://nix.dev/install-nix)
# 2. Download this file, and name it for example `fireblocks-mpc-lib-wasm32-wasi.nix`
# 3. Run `nix-shell fireblocks-mpc-lib-wasm32-wasi.nix`.
# 4. Run `wasitest` inside the nix-shell environment to run the paillier benchmark.
{ pkgs ? import (builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/51d906d2341c9e866e48c2efcaac0f2d70bfd43e.tar.gz";
sha256 = "16nmvxfiyna5y9gwd2i3bhkpbn0nn37i481g53zc0ycw67k268sv";
}) {}
, openssl-src ? (builtins.fetchTarball {
url = "https://github.com/openssl/openssl/archive/e3d897d3fa3b48bb835fab0665a435469beea7ae.tar.gz";
sha256 = "128py0kpvg5waadgp575lnbm2jfbjp685xx1i2bap2bwap0h68vs";
})
, openssl-wasm-src ? (builtins.fetchTarball {
url = "https://github.com/jedisct1/openssl-wasm/archive/72ca3f2c90777bf860801e11da75219d11e9b4d7.tar.gz";
sha256 = "10jx2fdmy2x2il0g0m9wp08g62lkxvfa5i042pjrhqhc3hbfavwp";
})
, fireblocks-mpc-lib-src ? (builtins.fetchTarball {
url = "https://github.com/fireblocks/mpc-lib/archive/84b7fb83502a998703b6ceb113273fc20fa55b7b.tar.gz";
sha256 = "13inkl865dcxhib68zyl3ghfzcqlwhhza647v92cxhw5dnm0537n";
})
}:
let
paillier-benchmark-cpp = pkgs.writeText "paillier-benchmark.cpp" ''
#include <iostream>
#include "crypto/paillier/paillier.h"
using Clock = std::conditional<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock>::type;
int main() {
auto before = Clock::now();
paillier_public_key_t* paillier_pub = NULL;
paillier_private_key_t* paillier_priv = NULL;
long paillier_res = paillier_generate_key_pair(2048, &paillier_pub, &paillier_priv);
if (paillier_res != PAILLIER_SUCCESS) {
std::cout << "Failed to generate paillier keypair\n";
} else {
std::cout << "Successfully generated paillier keypair\n";
}
auto after = Clock::now();
std::cout << "Time passed: " << std::chrono::duration_cast<std::chrono::milliseconds>(after - before).count() << " ms\n";
}
'';
openssl-wasm = pkgs.runCommand "openssl-wasm" {
src = openssl-src;
patches = "${openssl-wasm-src}/patches";
buildInputs = [ pkgs.zig pkgs.perl ];
FEATURE_FLAGS = "no-asm no-async no-egd no-ktls no-module no-posix-io no-secure-memory no-shared no-sock no-stdio no-thread-pool no-threads no-ui-console no-weak-ssl-ciphers";
AR = "zig ar";
RANLIB = "zig ranlib";
CC = "zig cc --target=wasm32-wasi";
CFLAGS = "-Ofast -Werror -Qunused-arguments -Wno-shift-count-overflow";
CPPFLAGS = "-D_WASI_EMULATED_GETPID -Dgetuid=getpagesize -Dgeteuid=getpagesize -Dgetgid=getpagesize -Dgetegid=getpagesize";
CXXFLAGS = "-Werror -Qunused-arguments -Wno-shift-count-overflow";
LDFLAGS = "-s -lwasi-emulated-getpid";
XDG_CACHE_HOME = ".cache";
CROSS_COMPILE = "";
} ''
cp -r $src/* .
chmod -R u+rwx .
for patch in "$patches"/*.patch; do
patch -p1 < "$patch"
done
perl Configure --banner="wasm32-wasi port" $FEATURE_FLAGS wasm32-wasi || exit 1
make "-j$NIX_BUILD_CORES"
mkdir -p $out/lib $out/include
mv *.a $out/lib
cp -r include/openssl $out/include
'';
fireblocks-mpc-wasm-objects = pkgs.runCommand "fireblocks-mpc-wasm-objects" {
src = "${fireblocks-mpc-lib-src}/src";
include = "${fireblocks-mpc-lib-src}/include";
buildInputs = [ pkgs.zig ];
XDG_CACHE_HOME = ".cache";
CROSS_COMPILE = "";
} ''
log() { IFS=' ' printf '\n%s\n' "$*"; eval "$@"; }
mkdir -p $out
cp -r $src/* $out
chmod -R u+rw $out
for cfile in $(find $out/common -name "*.c" | sort | grep -v curve25519.c); do
log zig cc --target=wasm32-wasi -Ofast -c -Wno-deprecated -I$include -I${openssl-wasm}/include $cfile -o $cfile.o
done
for cppfile in $(find $out/common -name "*.cpp" | sort | grep -v asymmetric_eddsa_cosigner_server.cpp | grep -v cmp_ecdsa_online_signing_service.cpp | grep -v eddsa_online_signing_service.cpp); do
log zig c++ --target=wasm32-wasi -Ofast -c -Wno-deprecated -Wno-format -I$include -I${openssl-wasm}/include $cppfile -o $cppfile.o
done
'';
fireblocks-mpc-lib = pkgs.runCommand "fireblocks-mpc-lib" {
objects = fireblocks-mpc-wasm-objects;
include = "${fireblocks-mpc-lib-src}/include";
buildInputs = [ pkgs.zig pkgs.binaryen ];
XDG_CACHE_HOME = ".cache";
CROSS_COMPILE = "";
} ''
log() { IFS=' ' printf '\n%s\n' "$*"; eval "$@"; }
mkdir -p $out/lib
objs=$(find $objects/common -name "*.o" | sort | paste -sd' ' -)
log zig c++ --target=wasm32-wasi -Ofast -s -lwasi-emulated-getpid -I$include ${paillier-benchmark-cpp} ${openssl-wasm}/lib/libcrypto.a $objs -o $out/lib/mpc.wasm
log wasm-opt -O3 -o $out/lib/mpc.wasm $out/lib/mpc.wasm
'';
nodejs-wasi-test = pkgs.writeText "wasitest.js" ''
const fs = require('fs')
const { WASI } = require('wasi')
main()
async function main() {
const wasi = new WASI({ version: 'preview1' })
const { instance } = await WebAssembly.instantiate(
fs.readFileSync('${fireblocks-mpc-lib}/lib/mpc.wasm'),
wasi.getImportObject()
)
wasi.start(instance)
}
'';
in pkgs.mkShell {
mpclib = fireblocks-mpc-lib;
buildInputs = [
(pkgs.writeShellScriptBin "wasitest" ''
echo "test.js: ${nodejs-wasi-test}"
echo "main.cpp: ${paillier-benchmark-cpp}"
echo "mpc.wasm: ${fireblocks-mpc-lib}/lib/mpc.wasm"
echo "---"
echo "Running wasm32-wasi test..."
NODE_NO_WARNINGS=1 ${pkgs.nodejs_21}/bin/node ${nodejs-wasi-test}
'')
];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment