├── .dockerignore ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── README.md ├── build.sh ├── libc-stub ├── Cargo.toml └── src │ └── lib.rs ├── run.js └── src └── lib.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | wasm_sodium.js 3 | wasm_sodium_bg.js 4 | wasm_sodium_bg.wasm 5 | *.d.ts 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "dtoa" 3 | version = "0.4.2" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "itoa" 8 | version = "0.4.1" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | 11 | [[package]] 12 | name = "libc" 13 | version = "0.2.41" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | 16 | [[package]] 17 | name = "libc-stub" 18 | version = "0.1.0" 19 | dependencies = [ 20 | "wasm-bindgen 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)", 21 | ] 22 | 23 | [[package]] 24 | name = "libsodium-sys" 25 | version = "0.0.16" 26 | source = "git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32#25ef676224fec702c5664ff37e489f406b45d43e" 27 | dependencies = [ 28 | "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "pkg-config" 34 | version = "0.3.11" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | 37 | [[package]] 38 | name = "proc-macro2" 39 | version = "0.4.3" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | dependencies = [ 42 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 43 | ] 44 | 45 | [[package]] 46 | name = "quote" 47 | version = "0.6.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "serde" 55 | version = "1.0.59" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | 58 | [[package]] 59 | name = "serde_derive" 60 | version = "1.0.59" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "syn 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "serde_json" 70 | version = "1.0.17" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | dependencies = [ 73 | "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 74 | "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 75 | "serde 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)", 76 | ] 77 | 78 | [[package]] 79 | name = "sodiumoxide" 80 | version = "0.0.16" 81 | source = "git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32#25ef676224fec702c5664ff37e489f406b45d43e" 82 | dependencies = [ 83 | "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "libsodium-sys 0.0.16 (git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32)", 85 | "serde 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)", 86 | ] 87 | 88 | [[package]] 89 | name = "syn" 90 | version = "0.14.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "quote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 96 | ] 97 | 98 | [[package]] 99 | name = "unicode-xid" 100 | version = "0.1.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | 103 | [[package]] 104 | name = "wasm-bindgen" 105 | version = "0.2.10" 106 | source = "git+https://github.com/alexcrichton/wasm-bindgen#dd76707ea1a3e9d4d0738e198b4f2fc9d93a8126" 107 | dependencies = [ 108 | "wasm-bindgen-macro 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)", 109 | ] 110 | 111 | [[package]] 112 | name = "wasm-bindgen-backend" 113 | version = "0.2.10" 114 | source = "git+https://github.com/alexcrichton/wasm-bindgen#dd76707ea1a3e9d4d0738e198b4f2fc9d93a8126" 115 | dependencies = [ 116 | "proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 117 | "quote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "syn 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "wasm-bindgen-shared 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)", 121 | ] 122 | 123 | [[package]] 124 | name = "wasm-bindgen-macro" 125 | version = "0.2.10" 126 | source = "git+https://github.com/alexcrichton/wasm-bindgen#dd76707ea1a3e9d4d0738e198b4f2fc9d93a8126" 127 | dependencies = [ 128 | "proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "quote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "syn 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "wasm-bindgen-backend 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)", 132 | ] 133 | 134 | [[package]] 135 | name = "wasm-bindgen-shared" 136 | version = "0.2.10" 137 | source = "git+https://github.com/alexcrichton/wasm-bindgen#dd76707ea1a3e9d4d0738e198b4f2fc9d93a8126" 138 | dependencies = [ 139 | "serde 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "serde_derive 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)", 141 | ] 142 | 143 | [[package]] 144 | name = "wasm-sodium" 145 | version = "0.1.0" 146 | dependencies = [ 147 | "libc-stub 0.1.0", 148 | "sodiumoxide 0.0.16 (git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32)", 149 | "wasm-bindgen 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)", 150 | ] 151 | 152 | [metadata] 153 | "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" 154 | "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" 155 | "checksum libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8ebf8343a981e2fa97042b14768f02ed3e1d602eac06cae6166df3c8ced206" 156 | "checksum libsodium-sys 0.0.16 (git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32)" = "" 157 | "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" 158 | "checksum proc-macro2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a45f2f0ae0b5757f6fe9e68745ba25f5246aea3598984ed81d013865873c1f84" 159 | "checksum quote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e53eeda07ddbd8b057dde66d9beded11d0dfda13f0db0769e6b71d6bcf2074e" 160 | "checksum serde 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)" = "2a4d976362a13caad61c38cf841401d2d4d480496a9391c3842c288b01f9de95" 161 | "checksum serde_derive 1.0.59 (registry+https://github.com/rust-lang/crates.io-index)" = "94bb618afe46430c6b089e9b111dc5b2fcd3e26a268da0993f6d16bea51c6021" 162 | "checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" 163 | "checksum sodiumoxide 0.0.16 (git+https://github.com/alexcrichton/sodiumoxide?branch=wasm32)" = "" 164 | "checksum syn 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99d991a9e7c33123925e511baab68f7ec25c3795962fe326a2395e5a42a614f0" 165 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 166 | "checksum wasm-bindgen 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)" = "" 167 | "checksum wasm-bindgen-backend 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)" = "" 168 | "checksum wasm-bindgen-macro 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)" = "" 169 | "checksum wasm-bindgen-shared 0.2.10 (git+https://github.com/alexcrichton/wasm-bindgen)" = "" 170 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-sodium" 3 | version = "0.1.0" 4 | authors = ["Alex Crichton "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | wasm-bindgen = "0.2" 11 | 12 | # A fork of `sodiumoxide` which has been tweaked for wasm32-unknown-unknown 13 | # support. It's a bit questionable how it's all supported but for now it should 14 | # work. The main change here is to avoid importing types from the `libc` crate 15 | # and instead define them locally. Once `clang` stabilizes its 16 | # `wasm32-unknown-unknown-wasm` target we can start filling out the `libc` crate 17 | # and we won't need the fork any more, it'll work natively (mostly). 18 | # 19 | # One final fix here was to avoid using `libc::strlen` and instead define it 20 | # in Rust. 21 | sodiumoxide = { git = 'https://github.com/alexcrichton/sodiumoxide', branch = 'wasm32' } 22 | 23 | libc-stub = { path = 'libc-stub' } 24 | 25 | [profile.release] 26 | lto = true 27 | opt-level = 's' 28 | panic = 'abort' 29 | 30 | [patch.crates-io] 31 | wasm-bindgen = { git = 'https://github.com/alexcrichton/wasm-bindgen' } 32 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update -y 4 | RUN apt-get install -y \ 5 | g++ \ 6 | make \ 7 | cmake \ 8 | curl \ 9 | xz-utils \ 10 | python 11 | 12 | WORKDIR /llvm/build 13 | RUN curl http://releases.llvm.org/6.0.0/llvm-6.0.0.src.tar.xz | \ 14 | tar xJf - -C /llvm --strip-components 1 15 | RUN mkdir /llvm/tools/clang 16 | RUN curl http://releases.llvm.org/6.0.0/cfe-6.0.0.src.tar.xz | \ 17 | tar xJf - -C /llvm/tools/clang --strip-components 1 18 | RUN cmake .. \ 19 | -DCMAKE_BUILD_TYPE=Release \ 20 | -DCMAKE_INSTALL_PREFIX=/clang \ 21 | -DLLVM_TARGETS_TO_BUILD=X86 \ 22 | -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly 23 | RUN make -j $(nproc) 24 | RUN make install 25 | 26 | # Install Rust as we'll use it later. We'll also be cribbing `lld` out of Rust's 27 | # sysroot to use when compiling libsodium 28 | ENV CARGO_HOME /cargo 29 | ENV RUSTUP_HOME /rustup 30 | RUN curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly 31 | ENV PATH $PATH:/cargo/bin:/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin 32 | RUN rustup target add wasm32-unknown-unknown 33 | 34 | ENV CC /clang/bin/clang 35 | 36 | WORKDIR / 37 | RUN apt-get install -y git 38 | RUN git clone https://github.com/jfbastien/musl 39 | WORKDIR /musl 40 | RUN git reset --hard d312ecae 41 | ENV CFLAGS -O3 --target=wasm32-unknown-unknown-wasm -nostdlib -Wl,--no-entry 42 | RUN CFLAGS="$CFLAGS -Wno-error=pointer-sign" ./configure --prefix=/musl-sysroot wasm32 43 | RUN make -j$(nproc) install 44 | 45 | WORKDIR / 46 | RUN curl https://download.libsodium.org/libsodium/releases/libsodium-1.0.16.tar.gz | tar xzf - 47 | WORKDIR /libsodium-1.0.16 48 | RUN CFLAGS="$CFLAGS --sysroot=/musl-sysroot -DSODIUM_STATIC"\ 49 | ./configure \ 50 | --host=asmjs \ 51 | --prefix=/musl-sysroot \ 52 | --without-pthreads \ 53 | --enable-minimal \ 54 | --disable-asm \ 55 | --disable-ssp 56 | RUN make -j$(nproc) install 57 | ENV SODIUM_LIB_DIR /musl-sysroot/lib 58 | ENV SODIUM_STATIC 1 59 | RUN rustup self uninstall -y 60 | ENV PATH /rust/bin:$PATH 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm32-unknown-unknown and sodiumoxide 2 | 3 | A proof-of-concept repository showing how libsodium and the sodiumoxide bindings 4 | can be used in the browser with the wasm32-unknown-unknown target. 5 | 6 | To test this out you'll need: 7 | 8 | * A Linux machine 9 | * The `docker` command 10 | * A nightly Rust compiler (`rustup update nightly`) 11 | * The wasm32 target (`rustup target add wasm32-unknown-unknown`) 12 | * The `wasm-bindgen` CLI command (`cargo install wasm-bindgen-cli`) 13 | * Node.js with wasm support 14 | 15 | And with all that in place you can execute the example with: 16 | 17 | ``` 18 | ./build.sh 19 | ``` 20 | 21 | And you should see something like: 22 | 23 | ``` 24 | ... 25 | + node run.js 26 | 10 randomly generated bytes are [132, 50, 0, 212, 16, 153, 236, 63, 8, 107] 27 | sha256("Hello, World!") = dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f 28 | ``` 29 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | # Build our docker container we'll compile wasm in. 4 | # 5 | # The primary need for this is a version of `clang` that supports wasm, see 6 | # comments in the `Dockerfile` for more info 7 | docker build \ 8 | --rm \ 9 | --tag wasm-sodium-test \ 10 | . 11 | 12 | # Use our docker container to compile to wasm. This is intended to share files 13 | # with the host so the output will show up in this directory 14 | mkdir -p target 15 | docker run \ 16 | --user $(id -u):$(id -g) \ 17 | --volume `pwd`:/c:ro \ 18 | --volume `pwd`/target:/c/target \ 19 | --volume $HOME/.cargo:/cargo \ 20 | --workdir /c \ 21 | --volume `rustc +nightly --print sysroot`:/rust:ro \ 22 | --interactive \ 23 | --tty \ 24 | --rm \ 25 | wasm-sodium-test \ 26 | cargo build --target wasm32-unknown-unknown --release 27 | 28 | # Now that we've finished compiling, execute `wasm-bindgen` and then run it 29 | # through `node.js` to get some examples. 30 | wasm-bindgen --nodejs --out-dir . \ 31 | target/wasm32-unknown-unknown/release/wasm_sodium.wasm 32 | 33 | node run.js 34 | -------------------------------------------------------------------------------- /libc-stub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libc-stub" 3 | version = "0.1.0" 4 | authors = ["Alex Crichton "] 5 | 6 | [dependencies] 7 | wasm-bindgen = "0.2" 8 | -------------------------------------------------------------------------------- /libc-stub/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate is a hack and should not exist! 2 | //! 3 | //! Ok with that out of the way let's see what's going on here. The libsodium 4 | //! library is compiled with a C compiler (clang) and sort of expects to link 5 | //! against musl. In reality we compiled it in such a way that is didn't find 6 | //! most of its functionality (aka optional symbols are all deduced to not 7 | //! exist). We won't link to musl as musl has more of a runtime than we'd like. 8 | //! 9 | //! Despite this the libsodium library will still reference some global symbols 10 | //! it expects from the C library. Things like `abort` or `__errno_location`. 11 | //! Again, these are all defined by musl itself, but for now we're not linking 12 | //! that in. The MUSL library currently assumes a generic `__syscall` abi which 13 | //! is a bit unfortunate, we don't want to deal with that at all! In any case.. 14 | //! 15 | //! So to actually get these symbols resolved so we can instantiate the module 16 | //! at runtime the definition has to live somewhere. Currently this opts to have 17 | //! that definition live in Rust in this crate. 18 | //! 19 | //! This isn't great and is a massive pain point around integration with C right 20 | //! now. It's not clear how these symbols are to be defined on the 21 | //! `wasm32-unknown-unknown-wasm` target in C. I at least haven't seen a lot of 22 | //! great examples of how to use that target in C... 23 | //! 24 | //! More comments on each function below! 25 | 26 | // Nightly features needed to implement this crate 27 | #![feature(allocator_api)] 28 | 29 | // Nightly features required by `wasm_bindgen` currently 30 | #![feature(proc_macro, wasm_custom_section, wasm_import_module)] 31 | 32 | #![allow(private_no_mangle_fns)] 33 | 34 | extern crate wasm_bindgen; 35 | 36 | use wasm_bindgen::prelude::*; 37 | 38 | use std::ffi::CStr; 39 | use std::heap::{GlobalAlloc, Global, Layout}; 40 | use std::mem; 41 | use std::slice; 42 | 43 | // Generic function which references the libc functions to avoid them being 44 | // optimized away, hopefully one day this pattern will also allow us to avoid 45 | // exporting the symbols below. 46 | pub fn foo() -> usize { 47 | __errno_location as usize + 48 | abort as usize + 49 | __assert_fail as usize + 50 | malloc as usize + 51 | free as usize + 52 | open as usize + 53 | fstat as usize + 54 | read as usize + 55 | close as usize + 56 | fcntl as usize 57 | } 58 | 59 | // This is used to access `errno` and is typically thread-local, but only one 60 | // thread on wasm so we can make it a global 61 | #[no_mangle] 62 | unsafe extern fn __errno_location() -> *mut i32 { 63 | static mut ERRNO: i32 = 0; 64 | &mut ERRNO 65 | } 66 | 67 | // This is, well, `abort`. It can't return. 68 | #[no_mangle] 69 | unsafe extern fn abort() -> ! { 70 | wasm_bindgen::throw("abort"); 71 | } 72 | 73 | // Shim called by the `assert` macro in C, we just send it off to `throw` like 74 | // `abort` above 75 | #[no_mangle] 76 | unsafe extern fn __assert_fail( 77 | msg: *const i8, 78 | _file: *const i8, 79 | _line: i32, 80 | _func: *const i8, 81 | ) -> ! { 82 | let s = CStr::from_ptr(msg as *const _); 83 | wasm_bindgen::throw(s.to_str().unwrap_or("assert in C tripped")) 84 | } 85 | 86 | // Good ol' malloc and free. Looks like libsodium will do some memory 87 | // allocation. That's handled here by routing to Rust's global memory allocator. 88 | #[no_mangle] 89 | unsafe extern fn malloc(a: usize) -> *mut u8 { 90 | let size = a + mem::size_of::(); 91 | let layout = match Layout::from_size_align(size, mem::align_of::()) { 92 | Ok(n) => n, 93 | Err(_) => return 0 as *mut u8, 94 | }; 95 | let ptr = Global.alloc(layout) as *mut usize; 96 | if ptr.is_null() { 97 | return ptr as *mut u8 98 | } 99 | *ptr.offset(0) = size; 100 | ptr.offset(1) as *mut u8 101 | } 102 | 103 | #[no_mangle] 104 | unsafe extern fn free(ptr: *mut u8) { 105 | let ptr = (ptr as *mut usize).offset(-1); 106 | let size = *ptr.offset(0); 107 | let align = mem::size_of::(); 108 | let layout = Layout::from_size_align_unchecked(size, align); 109 | Global.dealloc(ptr as *mut _, layout); 110 | } 111 | 112 | // Ok this is where functions get weird. 113 | // 114 | // Ideally we're defining as few functions as possible here, somehow coercing 115 | // libsodium to believe it's in a very limited environment that doesn't have 116 | // things like mprotect. We did a mostly good job of that but libsodium's random 117 | // support is currently unconditionally included and the absolute fallback 118 | // implementation is a dance of open/close/fstat/etc. 119 | // 120 | // These functions all exist to basically *only* support libsodium's 121 | // requirements for a random number generator through `read`. These are not 122 | // correct or valid implementations in general and probably aren't even correct 123 | // for libsodium. This is the biggest hack of all! 124 | 125 | #[no_mangle] 126 | unsafe extern fn open(_a: i32, _b: i32) -> i32 { 127 | // TODO: check that the filename is `/dev/random` and only return an fd for 128 | // that, but this is called with a varargs ABI so difficult to check... 129 | 3 130 | } 131 | 132 | // The current minimal subset needed to define `st_mode` to get past checks in 133 | // libsodium. 134 | #[allow(non_camel_case_types)] 135 | pub struct stat { 136 | pub st_dev: i64, 137 | pub __std_dev_padding: u32, 138 | pub __st_ino_truncated: u32, 139 | pub st_mode: u32, 140 | } 141 | 142 | #[no_mangle] 143 | unsafe extern fn fstat(fd: i32, s: *mut stat) -> i32 { 144 | if fd == 3 { 145 | (*s).st_mode = 0o20000; // make ST_ISCHR pass in libsodium 146 | 0 147 | } else { 148 | -1 149 | } 150 | } 151 | 152 | #[no_mangle] 153 | unsafe extern fn close(fd: i32) -> i32 { 154 | if fd == 3 { 0 } else { -1 } 155 | } 156 | 157 | #[no_mangle] 158 | unsafe extern fn fcntl(_: i32, _: i32, _: i32) -> i32 { 159 | 0 160 | } 161 | 162 | // Note that this binding is node.js specific, you'd want to use a tweaked 163 | // version for web browsers calling `crypto.getRandomValues` 164 | #[wasm_bindgen(module = "crypto", version = "*")] 165 | extern { 166 | fn randomFillSync(input: &mut [u8]); 167 | } 168 | 169 | #[no_mangle] 170 | unsafe extern fn read(fd: i32, bytes: *mut u8, amt: i32) -> i32 { 171 | if fd != 3 { 172 | return -1 173 | } 174 | 175 | let bytes = slice::from_raw_parts_mut(bytes, amt as usize); 176 | randomFillSync(bytes); 177 | amt 178 | } 179 | -------------------------------------------------------------------------------- /run.js: -------------------------------------------------------------------------------- 1 | const wasm = require('./wasm_sodium'); 2 | wasm.run(); 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro, wasm_custom_section, wasm_import_module)] 2 | 3 | extern crate sodiumoxide; 4 | extern crate wasm_bindgen; 5 | extern crate libc_stub; // see comments on this crate for what this is 6 | 7 | use std::fmt::{self, Write}; 8 | 9 | use wasm_bindgen::prelude::*; 10 | 11 | #[wasm_bindgen] 12 | extern { 13 | #[wasm_bindgen(js_namespace = console)] 14 | fn log(a: &str); 15 | } 16 | 17 | macro_rules! console_log { 18 | ($($t:tt)*) => (log(&format!($($t)*))) 19 | } 20 | 21 | #[wasm_bindgen] 22 | pub fn run() { 23 | sodiumoxide::init().unwrap(); 24 | 25 | // Generate some random bytes 26 | // 27 | // NB the random byte generator is very low quality, it's implemented in 28 | // the `libc-shim` crate via `read` currently. 29 | let bytes = sodiumoxide::randombytes::randombytes(10); 30 | console_log!("10 randomly generated bytes are {:?}", bytes); 31 | 32 | // Generate a sha256 digest 33 | let mut h = sodiumoxide::crypto::hash::sha256::State::new(); 34 | h.update(b"Hello, World!"); 35 | let digest = h.finalize(); 36 | console_log!("sha256(\"Hello, World!\") = {}", AsHex(digest.as_ref())); 37 | } 38 | 39 | struct AsHex<'a>(&'a [u8]); 40 | 41 | impl<'a> fmt::Display for AsHex<'a> { 42 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 | for &byte in self.0.iter() { 44 | f.write_char(btoc(byte >> 4))?; 45 | f.write_char(btoc(byte))?; 46 | } 47 | return Ok(()); 48 | 49 | fn btoc(a: u8) -> char { 50 | let a = a & 0xf; 51 | match a { 52 | 0...9 => (b'0' + a) as char, 53 | _ => (b'a' + a - 10) as char, 54 | } 55 | } 56 | } 57 | } 58 | --------------------------------------------------------------------------------