From 5ac58d30a4b04e49c3acafe1127e37ebc0dc0a0c Mon Sep 17 00:00:00 2001 From: eschorn1 Date: Thu, 21 Mar 2024 17:07:10 -0500 Subject: [PATCH] wasm init --- .gitignore | 16 ++++++------ Cargo.toml | 2 +- wasm/Cargo.toml | 34 +++++++++++++++++++++++++ wasm/README.md | 17 +++++++++++++ wasm/src/lib.rs | 51 ++++++++++++++++++++++++++++++++++++++ wasm/www/bootstrap.js | 5 ++++ wasm/www/index.html | 40 ++++++++++++++++++++++++++++++ wasm/www/index.js | 18 ++++++++++++++ wasm/www/package.json | 39 +++++++++++++++++++++++++++++ wasm/www/webpack.config.js | 14 +++++++++++ 10 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 wasm/Cargo.toml create mode 100644 wasm/README.md create mode 100644 wasm/src/lib.rs create mode 100644 wasm/www/bootstrap.js create mode 100644 wasm/www/index.html create mode 100644 wasm/www/index.js create mode 100644 wasm/www/package.json create mode 100644 wasm/www/webpack.config.js diff --git a/.gitignore b/.gitignore index 5399fa4..5b431b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,9 @@ -/target /.idea -/fuzz/corpus/ -/fuzz/Cargo.lock -/fuzz/target/ -/fuzz/artifacts -/fuzz/coverage -/dudect/Cargo.lock -/dudect/target/ -/ct_cm4/target/ **/Cargo.lock +**/artifacts +**/corpus +**/coverate +**/target +**/pkg +**/node_modules +**/package-lock.json diff --git a/Cargo.toml b/Cargo.toml index e43b6e0..a803358 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -workspace = { members = ['ffi'], exclude = ["ct_cm4", "dudect", "fuzz"] } +workspace = { members = ['ffi'], exclude = ["ct_cm4", "dudect", "fuzz", "wasm"] } [package] name = "fips203" diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml new file mode 100644 index 0000000..3085d03 --- /dev/null +++ b/wasm/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "fips203-wasm" +version = "0.1.3" +authors = ["Eric Schorn "] +description = "Sample web page utilizing FIPS 203 code" +repository = "" +publish = false +edition = "2021" + + +[lib] +crate-type = ["cdylib", "rlib"] + + +[features] +default = ["console_error_panic_hook"] + + +[dependencies] +wasm-bindgen = "0.2.84" +fips203 = { path = "../../fips203", default-features = false, features = ["ml-kem-512"] } +rand_chacha = "0.3.1" +console_error_panic_hook = { version = "0.1.7", optional = true } +rand = "0.8.5" +getrandom = { version = "0.2", features = ["js"] } +hex = "0.4.3" + + +[dev-dependencies] +wasm-bindgen-test = "0.3.34" + + +[profile.release] +opt-level = "s" diff --git a/wasm/README.md b/wasm/README.md new file mode 100644 index 0000000..8829e51 --- /dev/null +++ b/wasm/README.md @@ -0,0 +1,17 @@ +One-off installation + +~~~ +$ cargo install wasm-pack +$ sudo npm install npm@latest -g +~~~ + +To run: + +~~~ +$ cd wasm # this directory +$ wasm-pack build +$ cd www +$ npm install +$ export NODE_OPTIONS=--openssl-legacy-provider +$ npm run start +~~~ diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 0000000..74364e3 --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,51 @@ +use fips203::ml_kem_512; +// Could also be ml_kem_768 or ml_kem_1024. +use fips203::traits::{Decaps, Encaps, KeyGen, SerDes}; +use rand_chacha::rand_core::SeedableRng; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn run(seed: &str) -> String { + let seed = seed.parse(); + if seed.is_err() { return "Unable to parse number".to_string(); }; + let seed = seed.unwrap(); + + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + + // Alice runs `key_gen()` and then serializes the encaps key `ek` for Bob (to bytes). + let (alice_ek, alice_dk) = ml_kem_512::KG::try_keygen_with_rng_vt(&mut rng).expect("keygen failed"); + let alice_ek_bytes = alice_ek.into_bytes(); + + // Alice sends the encaps key `ek_bytes` to Bob. + let bob_ek_bytes = alice_ek_bytes; + + // Bob deserializes the encaps `ek_bytes` and then runs `encaps() to get the shared + // secret `ssk` and ciphertext `ct`. He serializes the ciphertext `ct` for Alice (to bytes). + let bob_ek = ml_kem_512::EncapsKey::try_from_bytes(bob_ek_bytes).expect("ek deser failed"); + let (bob_ssk, bob_ct) = bob_ek.try_encaps_with_rng_vt(&mut rng).expect("encaps failed"); + let bob_ct_bytes = bob_ct.into_bytes(); + + // Bob sends the ciphertext `ct_bytes` to Alice + let alice_ct_bytes = bob_ct_bytes; + + // Alice deserializes the ciphertext `ct` and runs `decaps()` with her decaps key + let alice_ct = ml_kem_512::CipherText::try_from_bytes(alice_ct_bytes).expect("ct deser failed"); + let alice_ssk = alice_dk.try_decaps_vt(&alice_ct).expect("decaps failed"); + + // Alice and Bob will now have the same secret key + assert_eq!(bob_ssk.into_bytes(), alice_ssk.clone().into_bytes(), "shared secret not identical"); + + let ek_hex = hex::encode(&bob_ek_bytes); + let ct_hex = hex::encode(&bob_ct_bytes); + let dk_hex = hex::encode(alice_dk.into_bytes()); + let ssk_hex = hex::encode(alice_ssk.into_bytes()); + + let s0 = format!("The seed used to generate the keys is: {}\n\n", seed); + let s1 = format!("The generated encaps key is: {}\n", ek_hex); + let s2 = format!("The generated decaps key is: {}\n\n", dk_hex); + let s3 = format!("The generated ciphertext is: {}\n", ct_hex); + let s4 = format!("The shared secret is: {}\n", ssk_hex); + let s5 = "Alice and Bob have an identical shared secret."; // because the above assert! passed + + (s0 + &s1 + &s2 + &s3 + &s4 + &s5).into() +} diff --git a/wasm/www/bootstrap.js b/wasm/www/bootstrap.js new file mode 100644 index 0000000..c9c7c75 --- /dev/null +++ b/wasm/www/bootstrap.js @@ -0,0 +1,5 @@ +// A dependency graph that contains any wasm must all be imported +// asynchronously. This `bootstrap.js` file does the single async import, so +// that no one else needs to worry about it again. +import("./index.js") + .catch(e => console.error("Error importing `index.js`:", e)); diff --git a/wasm/www/index.html b/wasm/www/index.html new file mode 100644 index 0000000..622779b --- /dev/null +++ b/wasm/www/index.html @@ -0,0 +1,40 @@ + + + + + FIPS 203 WASM Demo + + + + + + +

FIPS 203 WASM Demo

+ +

This page is a simple demonstration of code from the FIPS 203 + Rust crate running in the browser via wasm. This demo has a seedable random number generator so that + its results can be compared to + native test cases. Please see section 3.3 of the + FIPS 203 standard for critical + requirements on randomness when utilizing FIPS 203 in production. +

+ +

Enter a (u64 decimal) seed number below and click on 'Submit'. The encaps and decaps keys will be generated, + the encaps() function run to generate the ciphertext and shared secret, the decaps() function run to calculate + the 'other' shared secret, the shared secrets confirmed to match, and all resulting values displayed.

+ +

+

+ + +
+

+ +

+
+
+
+
+
diff --git a/wasm/www/index.js b/wasm/www/index.js
new file mode 100644
index 0000000..00da3c5
--- /dev/null
+++ b/wasm/www/index.js
@@ -0,0 +1,18 @@
+import * as wasm from "wasm";
+
+let wasmForm = document.getElementById("wasmForm");
+
+wasmForm.addEventListener("submit", (e) => {
+    e.preventDefault();
+
+    let seed = document.getElementById("seed");
+    let result = "";
+
+    if (seed.value) {
+        result = wasm.run(seed.value);
+        seed.value = "";
+        document.getElementById("wasm-canvas").innerHTML = result;
+    } else {
+        alert("Please enter a non-empty seed u64 decimal number");
+    }
+});
\ No newline at end of file
diff --git a/wasm/www/package.json b/wasm/www/package.json
new file mode 100644
index 0000000..956632f
--- /dev/null
+++ b/wasm/www/package.json
@@ -0,0 +1,39 @@
+{
+  "name": "create-wasm-app",
+  "version": "0.1.0",
+  "description": "create an app to consume rust-generated wasm packages",
+  "main": "index.js",
+  "bin": {
+    "create-wasm-app": ".bin/create-wasm-app.js"
+  },
+  "scripts": {
+    "build": "webpack --config webpack.config.js",
+    "start": "webpack-dev-server"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/rustwasm/create-wasm-app.git"
+  },
+  "keywords": [
+    "webassembly",
+    "wasm",
+    "rust",
+    "webpack"
+  ],
+  "author": "Ashley Williams ",
+  "license": "(MIT OR Apache-2.0)",
+  "bugs": {
+    "url": "https://github.com/rustwasm/create-wasm-app/issues"
+  },
+  "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
+  "dependencies": {
+    "wasm": "file:../pkg"
+  },
+  "devDependencies": {
+    "hello-wasm-pack": "^0.1.0",
+    "webpack": "^4.29.3",
+    "webpack-cli": "^3.1.0",
+    "webpack-dev-server": "^3.1.5",
+    "copy-webpack-plugin": "^5.0.0"
+  }
+}
diff --git a/wasm/www/webpack.config.js b/wasm/www/webpack.config.js
new file mode 100644
index 0000000..ad26038
--- /dev/null
+++ b/wasm/www/webpack.config.js
@@ -0,0 +1,14 @@
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const path = require('path');
+
+module.exports = {
+    entry: "./bootstrap.js",
+    output: {
+        path: path.resolve(__dirname, "dist"),
+        filename: "bootstrap.js",
+    },
+    mode: "development",
+    plugins: [
+        new CopyWebpackPlugin(['index.html'])
+    ],
+};