Interfacez-les tous !

WASM Interface Types : la promesse de l'universel

@m4d_z
alwaysdata

Une app
de messagerie

Mais voilà, on a un problème…

Donald…
… veut partager avec un ami…
… des documents sensibles.

Zero Knowledge Architecture

  • Chiffrement E2E
  • Authentification par clefs / certificats
  • Autorisations par token (Zero Knowledge Proof)

Du coup, on a un problème :

JavaScript

Les promesses de WebAssembly

  1. Exécution rapide
  2. Environnement sécurisé
  3. Code portable

WASM Security Model

JS est lent
(bah oui, quand même)

ASM.js : l’expérience

  • Sous-ensemble JavaScript
  • Très optimisé, mais très contraint
  • Très complexe à écrire manuellement

Emscripten

  • Toolchain
  • Compile depuis C/C++
  • Utilise LLVM
$ emcc hello_world.c
$ tree
.
├── a.out.html
└── a.out.js
$ node a.out.js
Hello World!

Et si on pouvait compiler
toute notre codebase Web ?

WebAssembly,
des modules pour tout changer

WASM Binary Format

0061 736d
0100 0000
0100 01
6002
7f7f
017f 07
0300 01
0002
0700 0103
6164 64
0000 07
0a00 0100
00
2000 2001
6a0b 0709
0000 04
6e61 6d65

WASM Text Format

(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))

Donc on a des modules

  • Headers → Déclaratifs
  • Statique → Déterministes
  • Types forts → Runtime Error Proof

La Sandbox

  • Contrôle des I/O
  • Isolation

Modèle de sécurité

  • Memory Safety
  • Control-Flow Integrity

Ajouter la couche de sécurité

PWA :
le chiffrement sécurisé

Utiliser un module WASM ?

  • embarquable
  • sécurisé
  • pas besoin de se limiter à JS

Libsodium:
le chiffrement moderne

Libsodium + emscripten =
WASM Crypto Module

JS Module

const _sodium = require('libsodium-wrappers');
(async() => {
  await _sodium.ready;
  const sodium = _sodium;

  console.log(sodium.VERSION);
})();

Clef Publique / Clef privée : Késako?

Chiffrement à clef publique

const SK = /* DONALD SECRET KEY */;
const PK = /* BORIS PUBLIC KEY */;
const _sodium = require('libsodium-wrapper');

let message = /* Never Gonna Give You Up! */;

(async () => {
  await _sodium.ready; const sodium = _sodium;

  const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
  const boris_pubkey = sodium.from_hex(PK);
  const donald_seckey = sodium.from_hex(SK);

  let ciphered = sodium.crypto_box_easy(message, nonce, boris_pubkey, donald_seckey);
  let payload = nonce.concat(ciphered);
});
Donald approuve !

Du code cross-platform

To Web, or not to Web?

  • Client JS
  • API Python
  • Clients mobiles
  • etc…

(le serveur n’accède pas aux contenus en ZKA)

Binders!

Problème : la lib doit être
compilée nativement (node-gyp)

WASM hors du navigateur:
WASI

  • Modules API bas-niveau pour tous les interpréteurs
  • Sandbox native pour tous les langages
  • Write once, Run everywhere

C’est le 5e Beatles
la 3e promesse de WASM

Securité

  • Sandbox → le code ne peut pas accéder à la couche OS
  • Exécution → déterministe + control-flow
  • Modules → isolation de la codebase

Problème :
WASM est en MVP

🍀 static types

  • 2 Integers
  • 2 Floats

I need Strings
💩 UTF-8

Linear Memory!

(un entier, c’est un pointeur mémoire)

Passage de valeurs depuis WASM vers JS :
simple mais fastidieux
(on a tout hardcodé dans le moteur)

Passage de valeurs depuis WASM
vers n’importe quoi :
on ne va pas hardcoder tous les codex

Besoin d’interfaces pour les I/O
(ce que fait WASI niveau système)

  • Intermediate Representation
  • Chaque langage se charge d’implémenter Interface Types
  • Le moteur WASM utilise les IR pour les échanges de données

The System Interface

  • System Calls Abstraction
  • Runtime emulating JS glue code / Browser
  • Security

Faites-le vous-même

WASM Interface Types
(traits)
Defines shared behavior in an abstract way

.WITX

Mon app offre une couche crypto unifiée
(avec le module libsodium dessous)

WITX: Interface Types Definition

;;; file://src/types/crypto.witx`
(use "errno.witx")

;;; Encoder
(module $crypto
  (@interface func (export "encode")
    (param $lh s32)
    (param $rh s32)
    (result $error $errno)
    (result $res s32)
  )
)

Rust à la rescousse:
Wiggle

Import

/// file://src/lib/main.rs

wiggle::from_witx!({
    witx: ["../types/crypto.witx"],
    ctx: CryptoCtx,
});

pub struct CryptoCtx {}

Implement

/// file://src/lib/main.rs

impl crypto::Crypto for CryptoCtx {
    fn encode(&self, lh: i32, rh: i32) -> Result<i32, types::Errno> {
        // Uses libsodium
    }
}

Link: Wasmtime linker

/// file://src/lib/main.rs

let mut linker = Linker::new(store);
linker.func("crypto", "encode", |x: i32, y: i32| {
    let ctx = crypto::CryptoCtx {};
    ctx.encode(x, y).unwrap()
})?;

linker.instantiate(&module)

Usage

/// file://src/app/messages_crypto.rs

#[link(wasm_import_module = "crypto")]
extern "C" {
    fn encode(lh: i32, rh: i32) -> i32;
}

#[no_mangle]
pub unsafe extern "C" fn enc_message(lh: i32, rh: i32) -> i32 {
    encode(lh, rh)
}

Alt Usage: WAT

;;; file://src/app/messages_crypto.wat

(module
  (import "crypto" "encode" (func $crypto_encode (param i32 i32) (result i32)))

  (func $enc_message (param $lhs i32) (param $rhs i32) (result i32)
    local.get $lhs
    local.get $rhs
    call $crypto_encode)
  (export "enc_message" (func $enc_message))
)
Du coup, mon module, je peux l'utiliser partout ?

Oui, mais…

  • Navigateur Web → oui, via JS
  • Node.js → oui, support natif
  • Rust → oui, support natif
  • Python, Ruby, PHP, Dotnet, etc → via wasmtime

Example : API Python

### file://src/api/messages_backend.py

import wasmtime

# Load our `crypto.wasm` file.
# This is loaded by the `wasmtime_py`.
import crypto

# Use it!
crypto.encode(a, b)

Write Once,
Run Anywhere

Le futur du Serverless (FaaS)

$ curl --location --request POST 'https://[::]/api/executables' \
--header 'Content-Type: application/octet-stream' \
--header 'SSVM_Description: Encoder' \
--data-binary 'crypto.wasm'
$ curl --location --request POST 'https://[::]/api/run/123/encode' \
--header 'Content-Type: text/plain' \
--data-raw "bXkgc2Vuc2l0aXZlIGRvY3VtZW50LmRvY3gK"

Open Standard
→ Bâtir l’écosystème

Web Platform!

  • HTML/DOM → Interfaces
  • CSS → Layouts/Style
  • JS → UI Thread
  • WASM → Shared Business Logics / Background
m4dz's avatar
m4dz

Paranoïd Web Dino · Tech Evangelist

alwaysdata logo
https://www.alwaysdata.com

Questions ?

Illustrations

m4dz, CC BY-SA 4.0

Interleaf images

Courtesy of Unsplash and Pexels contributors

Icons

  • Layout icons are from Entypo+
  • Content icons are from FontAwesome

Fonts

  • Cover Title: Sinzano
  • Titles: Argentoratum
  • Body: Mohave
  • Code: Fira Code

Tools

Powered by Reveal.js

Source code available at
https://git.madslab.net/talks