rust -> WebAssembly for web browsers missing features. scrypt + NaCl crypto_box, minimal, 30kb gzipped
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Your Name c943636141 more rust-ish error handling 2 weeks ago
src more rust-ish error handling 2 weeks ago
webworker first working version 2 weeks ago
.gitignore update build and readme 3 weeks ago
Cargo.toml first working version 2 weeks ago
README.md add file size log and demo html page 2 weeks ago
build.sh add file size log and demo html page 2 weeks ago
demo.html add file size log and demo html page 2 weeks ago

README.md

scrypt-x25519-wasm

Originally forked from https://github.com/MyEtherWallet/scrypt-wasm (last commit: 2018)

This is a minimal (less than 100kb, 30kb gzipped) webassembly blob which provides cryptography functions neccesary for:

  • passphrase-based key derivation
    • Scrypt memory-hard hash function
  • asymetric-key cryptography (public and private key)

dev-dependencies

IDK if you have to run this? You might.

rustup target add wasm32-unknown-unknown

Build WebWorker

./build.sh

Then the output of this build should be in the webworker folder.

This build script converts the wasm-bindgen output, which was designed to be an ECMAScript module, into a WebWorker. It needs to be a WebWorker because for large values of cpuAndMemoryCost for the scrypt hash function, it would cause the JavaScript vm to hang (thus blocking the UI thread in the browser), which is no good. We want to be able to display a loading animaton while the computer is performing the key derivation from the users seed.

Test

After building, python3 -m http.server -b 127.0.0.1 8080

Then navigate to http://localhost:8080/demo.html

Usage

Host the files inside the webworker folder at ./static/ on your web server:

/static/scryptWebWorker.js /static/scrypt.wasm

Load the webworker and set up access to it on your HTML page like this:

<script>
function randomBytesBase64(byteCount) {
    const array = new Uint8Array(byteCount);
    crypto.getRandomValues(array);
    return btoa(String.fromCharCode.apply(null, array));
}
scryptWebWorker = new Worker("./static/scryptWebWorker.js"); // , {"type": "module"}s
scryptWebWorkerPromises = {};
callScryptWebWorkerAsync = (functionName, parameters) => {
   const functionCallId = randomBytesBase64(4);
   let promise;
   promise = new Promise((resolve, reject) => {
      this.scryptWebWorkerPromises[functionCallId] = { promise, resolve, reject }; 
   });

   this.scryptWebWorker.postMessage({
      functionCallId: functionCallId,
      functionName: functionName,
      parameters: parameters
   });

   return promise;
};
scryptWebWorker.onmessage = (e) => {
   this.scryptWebWorkerPromises[e.data.functionCallId].resolve(e.data.result);
};

// ----------------------------------------------
// Then you may call it like this: 
// ----------------------------------------------

function utf8Base64(str) {
  const encoder = new TextEncoder();
  const uint8Array = encoder.encode(str);
  let binaryString = "";
  for (let i = 0; i < uint8Array.length; i++) {
    binaryString += String.fromCharCode(uint8Array[i]);
  }
  return window.btoa(binaryString);
}

testScryptHash = async () => {
    console.log(1)
  const cpuAndMemoryCost = 8192;
  const blockSize = 64;
  const parallelism = 1;
  const keyLength = 32;

  const result = await callScryptWebWorkerAsync(
   'scrypt', [
      utf8Base64("this is the string to be hashed"),
      utf8Base64("this is the salt"),
      cpuAndMemoryCost,
      blockSize,
      parallelism,
      keyLength
    ]
  )
  console.log(2)
  console.log(result)
};

testScryptHash();
</script>