jedisct1 / libhydrogen

A lightweight, secure, easy-to-use crypto library suitable for constrained environments.
https://libhydrogen.org
Other
608 stars 92 forks source link

WASM example usage #155

Closed simonarnell closed 1 day ago

simonarnell commented 5 days ago

It would be really handy to have example code of how to utilise libhydrogen's WASI output. I'm able to build the target, and use for the simple case of generating random numbers, where I'm just reading the returned int, see example below.

However being new to WASI and there not being many great examples online, I am struggling to pass a shared memory object between node and the Wasm runtime. In your hashing usage documentation, it is described that hydro_hash_hash expects an argument out. Therefore I ask that an example is provided that can walk a neophyte, such as myself, as to how to provide an appropriate structure for this to return a hash of a given string.

const { readFile } = require('node:fs/promises');
const { WASI } = require('node:wasi');
const { argv, env } = require('node:process');
const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {},
});

const importObj = wasi.getImportObject();

(async () => {
  const wasm = await WebAssembly.compile(
    await readFile('../../../../build/backend/vendor/libhydrogen/libhydrogen.wasm'),
  );
  const instance = await WebAssembly.instantiate(wasm, importObj);

  wasi.start(instance);
  console.log(instance.exports.hydro_random_uniform(20))
})();
simonarnell commented 1 day ago

In case it helps others, the below example works. In my case I was failing to understand that the WASI interface requires the WebAssembly to export an object called memory when its _start function is called. This can then be used for passing data between the two runtimes. In the example below, an initially zero filled array array, contains the hash of the MESSAGE string once hydro_hash_hash is called.

const { readFile } = require('node:fs/promises');
const { WASI } = require('node:wasi');
const { argv, env } = require('node:process');

const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {},
});

const imports = wasi.getImportObject();

(async () => {
  const wasm = await WebAssembly.compile(
    await readFile('../../../../build/backend/vendor/libhydrogen/libhydrogen.wasm')
  );
  const instance = await WebAssembly.instantiate(wasm, imports);
  wasi.start(instance);
  const { hydro_hash_hash, memory } = instance.exports
  const dv = new DataView(memory.buffer);
  const array = new Int32Array(dv.buffer, 0, 32)
  const CONTEXT = "Examples";
  const MESSAGE = "Arbitrary data to hash";
  hydro_hash_hash(array.byteOffset, array.length, Buffer.from(MESSAGE),
    Buffer.from(MESSAGE).length, Buffer.from(CONTEXT), null);
})();