Skip to content

Commit

Permalink
WIP: start exposing the new api alongside the old one
Browse files Browse the repository at this point in the history
  • Loading branch information
msprotz committed Jun 14, 2024
1 parent efc3e5e commit 5466a0d
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 51 deletions.
103 changes: 98 additions & 5 deletions js/MLS_JS.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
open Js_of_ocaml
open JsHelpers
open MLS_API

(* HELPERS *)

(* Effectful monadic operator with extra debugging for MLS_Result. *)
let (let*) r f =
match r with
| MLS_Result.Success s ->
Expand All @@ -12,14 +16,106 @@ let (let*) r f =
print_endline ("ProtocolError: " ^ s);
Js.null

let print_and_fail s =
(* Makes sure something shows up in the JS console *)
print_endline ("ERROR: " ^ s);
assert false

(* GLOBAL STATE: entroy, bytes instance, etc. *)

let entropy_state: Obj.t = Obj.repr ()

let extract_entropy: (MLS_Crypto_Builtins.hacl_star_bytes, Obj.t) MLS_API.entropy ref =
ref { extract_entropy = fun _ _ -> print_and_fail "Please call setEntropy first" }

let crypto_bytes_ = ref None

let crypto_bytes () =
match !crypto_bytes_ with
| Some cb -> cb
| None -> print_endline ("Must call setCiphersuite first"); assert false

(* CONVERSIONS *)

let framing_params_of_js o = {
encrypt = o##.encrypt;
padding_size = Z.of_int o##.padding_size;
authenticated_data = bytes_of_uint8array o##.authenticated_data;
}

let leaf_node_params_of_js o =
{ nothing_yet = () }

let commit_params_of_js o =
let proposals = Array.to_list o##.proposals in
let inline_tree = o##.inline_tree in
let force_update = o##.force_update in
let leaf_node_params = leaf_node_params_of_js o##.leaf_node_params in
{ proposals; inline_tree; force_update; leaf_node_params }

let js_of_create_commit_result { commit; welcome; group_info } = object%js
val commit = uint8array_of_bytes commit
val welcome = Js.Opt.option (Option.map uint8array_of_bytes welcome)
val group_info = uint8array_of_bytes group_info
end

let _ =
Js.export_all (object%js
method test: _ =
MLS_Test_Internal.test ()

(* NEW API: global state *)

method setCrypto (arg: _ Js.t) =
Js.Unsafe.global##._MyCrypto := arg

(* Expects a JS function that takes a Number and returns that many random
bytes as a UInt8Array. *)
method setEntropy (f: _ Js.t) =
extract_entropy := { extract_entropy = fun n state ->
let bytes = bytes_of_uint8array (Js.Unsafe.fun_call f [| Js.Unsafe.inject (Z.to_int n) |]) in
MLS_Result.Success bytes, state
}

(* Expects a JS string that contains the expected ciphersuite *)
method setCiphersuite (cs: _ Js.t) =
match Js.to_string cs with
| _ ->
(* TODO: actually offer more ciphersuites *)
if !crypto_bytes_ <> None then
print_and_fail "Cannot dynamically change ciphersuites";
crypto_bytes_ := Some MLS_Crypto_Builtins.(mk_concrete_crypto_bytes AC_mls_128_dhkemx25519_chacha20poly1305_sha256_ed25519)

(* NEW API: binders for MLS.API.fst (via MLS_API.ml) *)
method createCommit mls_group framing_params commit_params =
(* mls_group is left "as is" and is not roundtripped via serialization *)
let framing_params = framing_params_of_js framing_params in
let commit_params = commit_params_of_js commit_params in
let res, _entropy_state = create_commit (crypto_bytes ()) ()
(!extract_entropy) mls_group framing_params commit_params entropy_state
in
let* create_commit_result, mls_group = res in
Js.some object%js
val create_commit_result = js_of_create_commit_result create_commit_result
val mls_group = mls_group
end

method createAddProposal kp =
let* p = create_add_proposal (crypto_bytes ()) (bytes_of_uint8array kp) in
Js.some p

method createRemoveProposal group removed =
let* p = create_remove_proposal (crypto_bytes ()) group removed in
Js.some p

(* INTERNAL SELF-TEST *)

method test: _ =
MLS_Test_Internal.test ()

(* OLD API BASED ON MLS.fst / MLS.ml -- TODO: REMOVE *)

method currentEpoch (s: MLS.state) =
Z.to_int (MLS.current_epoch s)

method freshKeyPair1 (e: Typed_array.uint8Array Js.t) =
let e = bytes_of_uint8array e in
let* pub_key, priv_key = MLS.fresh_key_pair e in
Expand All @@ -39,9 +135,6 @@ let _ =
val hash = uint8array_of_bytes hash
end)

method currentEpoch (s: MLS.state) =
Z.to_int (MLS.current_epoch s)

method create1 (e: Typed_array.uint8Array Js.t) (credential: _ Js.t) (priv: MLS.signature_key)
(group_id: Js.js_string Js.t)
=
Expand Down
53 changes: 8 additions & 45 deletions js/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var debug = true;

////////////////////////////////////////////////////////////////////////////////
// MLS Lib //
// OLD MLS Lib //
////////////////////////////////////////////////////////////////////////////////

let freshKeyPairDebug = 0;
Expand Down Expand Up @@ -162,52 +162,9 @@ function HaclCrypto(Hacl) {
};
}

// WIP, TODO: port all primitives to node-crypto
function NodeCrypto(Hacl) {
return {
sha2_256_hash: (b) => node_crypto.createHash('sha256').update(b).digest(),

hkdf_sha2_256_extract: (salt, ikm) => Hacl.HKDF.extract_sha2_256(salt, ikm)[0],

hkdf_sha2_256_expand: (prk, info, size) => Hacl.HKDF.expand_sha2_256(prk, info, size)[0],

sha2_512_hash: (b) => node_crypto.createHash('sha512').update(b).digest(),

// const ecdh = node_crypto.createECDH("X25519");
// ecdh.setPrivateKey(sk);
// return new Uint8Array(ecdh.getPrivateKey().buffer);
ed25519_secret_to_public: (sk) => Hacl.Ed25519.secret_to_public(sk)[0],

ed25519_sign: (sk, msg) => Hacl.Ed25519.sign(sk, msg)[0],

ed25519_verify: (pk, msg, signature) => Hacl.Ed25519.verify(pk, msg, signature)[0],

chacha20_poly1305_encrypt: (key, iv, ad, pt) => {
let cipher = node_crypto.createCipheriv('chacha20-poly1305', key, iv, { authTagLength: 16 });
cipher.setAAD(ad);
let ct = cipher.update(pt);
cipher.final();
return [ new Uint8Array(ct.buffer), new Uint8Array(cipher.getAuthTag().buffer) ];
},

chacha20_poly1305_decrypt: (key, iv, ad, ct, tag) => {
let decipher = node_crypto.createDecipheriv("chacha20-poly1305", key, iv, { authTagLength: 16 });
decipher.setAAD(ad);
let pt = decipher.update(ct);
decipher.setAuthTag(tag);
try {
decipher.final();
return pt;
} catch (e) {
return null;
}
}
};
}

if (typeof module !== undefined)
module.exports = {
// MLS API
// OLD MLS API
freshKeyPair,
freshKeyPackage,
create,
Expand All @@ -217,6 +174,12 @@ if (typeof module !== undefined)
processGroupMessage,
processWelcomeMessage,
currentEpoch: MLS.currentEpoch,
// NEW MLS API
setEntropy: MLS.setEntropy,
setCiphersuite: MLS.setCiphersuite,
createCommit: MLS.createCommit,
createAddProposal: MLS.createAddProposal,
createRemoveProposal: MLS.createRemoveProposal,
// MLS Crypto API (the individual primitives)
setCrypto: MLS.setCrypto,
HaclCrypto,
Expand Down
2 changes: 1 addition & 1 deletion js/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var HaclWasm = require("./wasm/api.js");
////////////////////////////////////////////////////////////////////////////////

var test_main = () => {
// A demo of how to drive the high-level API.
// A demo of how to drive the (OLD) high-level API.
console.log("Page loaded");

// A self-test mostly for my own debugging.
Expand Down

0 comments on commit 5466a0d

Please sign in to comment.