Skip to content

Commit

Permalink
Basic WebAssembly support with minimal Javascript API mthom#615. Curr…
Browse files Browse the repository at this point in the history
…ently 6/12 crypto functions supported. Tested in browser with all default features disabled.
  • Loading branch information
Rujia Liu committed Sep 2, 2023
1 parent 66f6399 commit b778872
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 71 deletions.
20 changes: 18 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ categories = ["command-line-utilities"]
build = "build/main.rs"
rust-version = "1.63"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["ffi", "repl", "hostname", "tls", "http"]
default = ["ffi", "repl", "hostname", "tls", "http", "crypto-full"]
ffi = ["dep:libffi"]
repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
hostname = ["dep:hostname"]
tls = ["dep:native-tls"]
http = ["dep:hyper", "dep:reqwest"]
crypto-full = []

[build-dependencies]
indexmap = "1.0.2"
Expand Down Expand Up @@ -79,7 +83,19 @@ tokio = { version = "1.28.2", features = ["full"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.10", features = ["js"] }
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] }
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt"] }

[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
console_error_panic_hook = "0.1"
console_log = "1.0"
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4"
serde-wasm-bindgen = "0.5"
web-sys = { version = "0.3", features = [
"Document",
"Window",
"Element",
]}

[target.'cfg(target_os = "wasi")'.dependencies]
ring-wasi = { version = "0.16.25" }
Expand Down
48 changes: 32 additions & 16 deletions build/instructions_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,22 +496,28 @@ enum SystemClauseType {
CryptoDataHKDF,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
CryptoPasswordHash,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
CryptoCurveScalarMult,
#[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))]
Curve25519ScalarMult,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))]
CryptoDataEncrypt,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
CryptoCurveScalarMult,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
Ed25519Sign,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
Ed25519Verify,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
Ed25519NewKeyPair,
#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
Ed25519KeyPairPublicKey,
#[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))]
Curve25519ScalarMult,
#[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
FirstNonOctet,
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
Expand Down Expand Up @@ -1828,13 +1834,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallCryptoDataHash |
&Instruction::CallCryptoDataHKDF |
&Instruction::CallCryptoPasswordHash |
&Instruction::CallCryptoDataEncrypt |
&Instruction::CallCryptoDataDecrypt |
&Instruction::CallCryptoCurveScalarMult |
&Instruction::CallEd25519Sign |
&Instruction::CallEd25519Verify |
&Instruction::CallEd25519NewKeyPair |
&Instruction::CallEd25519KeyPairPublicKey |
&Instruction::CallCurve25519ScalarMult |
&Instruction::CallFirstNonOctet |
&Instruction::CallLoadHTML |
Expand Down Expand Up @@ -1891,6 +1891,17 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("call"), [atom(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataEncrypt |
&Instruction::CallCryptoDataDecrypt |
&Instruction::CallEd25519Sign |
&Instruction::CallEd25519Verify |
&Instruction::CallEd25519NewKeyPair |
&Instruction::CallEd25519KeyPairPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
}
//
&Instruction::ExecuteAtomChars |
&Instruction::ExecuteAtomCodes |
&Instruction::ExecuteAtomLength |
Expand Down Expand Up @@ -2056,13 +2067,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteCryptoDataHash |
&Instruction::ExecuteCryptoDataHKDF |
&Instruction::ExecuteCryptoPasswordHash |
&Instruction::ExecuteCryptoDataEncrypt |
&Instruction::ExecuteCryptoDataDecrypt |
&Instruction::ExecuteCryptoCurveScalarMult |
&Instruction::ExecuteEd25519Sign |
&Instruction::ExecuteEd25519Verify |
&Instruction::ExecuteEd25519NewKeyPair |
&Instruction::ExecuteEd25519KeyPairPublicKey |
&Instruction::ExecuteCurve25519ScalarMult |
&Instruction::ExecuteFirstNonOctet |
&Instruction::ExecuteLoadHTML |
Expand Down Expand Up @@ -2119,6 +2124,17 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("execute"), [atom(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataEncrypt |
&Instruction::ExecuteCryptoDataDecrypt |
&Instruction::ExecuteEd25519Sign |
&Instruction::ExecuteEd25519Verify |
&Instruction::ExecuteEd25519NewKeyPair |
&Instruction::ExecuteEd25519KeyPairPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
}
//
&Instruction::Deallocate => {
functor!(atom!("deallocate"))
}
Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,17 @@ mod targets;
pub mod types;

use instructions::instr;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn eval_code(s: &str) -> String {
use web_sys::console;
use machine::mock_wam::*;

let mut wam = Machine::with_test_streams();
let bytes = wam.test_load_string(s);
String::from_utf8_lossy(&bytes).to_string()
}
44 changes: 28 additions & 16 deletions src/machine/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4663,70 +4663,82 @@ impl Machine {
self.crypto_password_hash();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCryptoCurveScalarMult => {
self.crypto_curve_scalar_mult();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCryptoCurveScalarMult => {
self.crypto_curve_scalar_mult();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurve25519ScalarMult => {
self.curve25519_scalar_mult();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCurve25519ScalarMult => {
self.curve25519_scalar_mult();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataEncrypt => {
self.crypto_data_encrypt();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataEncrypt => {
self.crypto_data_encrypt();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataDecrypt => {
self.crypto_data_decrypt();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataDecrypt => {
self.crypto_data_decrypt();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCryptoCurveScalarMult => {
self.crypto_curve_scalar_mult();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCryptoCurveScalarMult => {
self.crypto_curve_scalar_mult();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallEd25519Sign => {
self.ed25519_sign();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteEd25519Sign => {
self.ed25519_sign();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallEd25519Verify => {
self.ed25519_verify();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteEd25519Verify => {
self.ed25519_verify();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallEd25519NewKeyPair => {
self.ed25519_new_key_pair();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteEd25519NewKeyPair => {
self.ed25519_new_key_pair();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
#[cfg(feature = "crypto-full")]
&Instruction::CallEd25519KeyPairPublicKey => {
self.ed25519_key_pair_public_key();
step_or_fail!(self, self.machine_st.p += 1);
}
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteEd25519KeyPairPublicKey => {
self.ed25519_key_pair_public_key();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurve25519ScalarMult => {
self.curve25519_scalar_mult();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCurve25519ScalarMult => {
self.curve25519_scalar_mult();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallFirstNonOctet => {
self.first_non_octet();
step_or_fail!(self, self.machine_st.p += 1);
Expand Down
13 changes: 13 additions & 0 deletions src/machine/mock_wam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,19 @@ impl Machine {
self.load_file(file.into(), stream);
self.user_output.bytes().map(|b| b.unwrap()).collect()
}

pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
use std::io::Read;

let stream = Stream::from_owned_string(
code.to_owned(),
&mut self.machine_st.arena,
);

self.load_file("<stdin>".into(), stream);
self.user_output.bytes().map(|b| b.unwrap()).collect()
}

}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,10 @@ impl Machine {
let user_output = Stream::stdout(&mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena);

#[cfg(not(target_os = "wasi"))]
#[cfg(not(target_arch = "wasm32"))]
let runtime = tokio::runtime::Runtime::new()
.unwrap();
#[cfg(target_os = "wasi")]
#[cfg(target_arch = "wasm32")]
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
Expand Down
Loading

0 comments on commit b778872

Please sign in to comment.