mymonero / mymonero-core-js

The JS library containing the Monero crypto plus lightwallet functions behind the official MyMonero apps
BSD 3-Clause "New" or "Revised" License
101 stars 103 forks source link

System for converting Monero C++ to JS via modern emscripten; C++ reimpl of major functions #41

Closed paulshapiro closed 5 years ago

paulshapiro commented 6 years ago

This PR replaces the existing hand-modified cryptonote_crypto_EMSCRIPTEN.js file with an automatically built MyMoneroCoreCpp.js and .wasm fileset. This is called by a modified cryptonote_utils.js file new file, MyMoneroCoreBridge.js.

This work is an incremental step towards the real overhaul of the API, in which the majority of mymonero_core_js implementation (including, for example, mnemonics) will be shifted to C++. The C++ work for that has basically been completed and is getting final testing and possibly additional minor functions (this reimplementation solves #13 and much of #18). In the meantime, this PR, which now only demonstrates reimplementing the initial function of cryptonote_crypto_EMSCRIPTEN by transpiling crypto-ops.c, is being made available for review given its essential functionality.

This PR solves e.g. #8, #7, #1, #50.

The C++ reimplementation (located at https://github.com/mymonero/mymonero-core-cpp) solves #13 (pending bulletproofs implementation stabilization), and since it hooks into Monero's cryptonote_core, it also includes fundamental support for hw devices (#18).

Most of the JS in this repo has been condensed into a single file: cryptonote_utils.js MyMoneroCoreBridge.js. This file was adapted from the old cryptonote_utils.js and now focuses on being a bridge to emscripten by managing dependency loading and serialization. An interface to this core bridge is provided in the familiar file monero_utils.js, which is the entrypoint for all core calls. monero_utils now exports a promise, the resolve of which must be waited upon before calls can be made, which have all been able to remain synchronous. Since monero_utils must be waited upon, synchronous higher level functions which require monero_utils such as the lazy key image generator factory accessor now take a resolveed monero_utils as an argument. If you're including monero_utils from an Electron renderer process, it automatically bridges to include the actual core bridge + wasm on the main process and relays err_msgs over IPC so that they get thrown on the renderer process rather than breaking the IPC call.

Many files have been removed… especially the various JS crypto implementations like nacl, sha3, mnemonics... Some fixes and additional features have been gained, such as a full range of mnemonic languages, and much better support for decoding mnemonics with misspellings.

There are some significant API changes, but the JSON bridge to C++ is extremely simple and almost equivalent in content to the existing JS APIs. This JSON API is fully documented in the readme at https://github.com/mymonero/mymonero-core-cpp.

paulshapiro commented 5 years ago

Yes, it's because emscripten now builds wasm instead of asm.js, which is must faster than the latter, but must be loaded asynchronously. If you want, you can build the library for asm.js instead (see the CMakeLists file.).

The Electron-related code snippets are merely there to facilitate calling the functions over IPC. There are no actual electron includes or special code. It just looks at a global and includes a very vanilla module to either throw or not throw. They don't affect your dependencies when you want to run it in any other environment. It's not optimized for MyMonero any more than the previous version of the library was, and in fact, we are receiving requests to add bridging to various other functions like decodeRct and are in the process of adding them as much as people are actually communicating their wishes with us. Given that our new setup is significantly faster than any asm.js build or hand-coded JS, and given the future bringing new implementations which are prohibitive to re-implement by hand in JS such as bulletproofs, we would like this library to support the various crypto utils cases going forward. However we have chosen to expose certain functions with their actual implementations in C++ in order to share code across implementations and in order to achieve maximal performance. Thanks for your question.

p0o commented 5 years ago

@paulshapiro Thanks for the good explanations. Just as a JS developer this API is not really looking good:

const args_str = '{"nettype_string":"MAINNET","from_address_string":"..."}';
const ret_string = Module.create_transaction(args_str);

Can the bindings be improved to something like below?

const ret_string = Module.createTransaction({nettypeString: "MAINNET"});
paulshapiro commented 5 years ago

@p0o that is not the API you should use. You're trying to interact directly with the emscripten module. A ton of work has been done so you don't have to...

p0o commented 5 years ago

@paulshapiro ah my bad, so I should use the functions in MyMoneroCoreBridge only? In that case I say it was better to write the tests with that API. Most devs would read the tests to know how to use the library.

paulshapiro commented 5 years ago

You're free to use it however you want :P

paulshapiro commented 5 years ago

And yeah docs for the core-js API here coming soon, feel free to PR since it's stable enough that we documented the JSON bridge

https://github.com/mymonero/mymonero-core-cpp - Readme - API Documentation

paulshapiro commented 5 years ago

I recently added a bunch of commonly requested crypto functions in this commit: https://github.com/mymonero/mymonero-core-js/commit/299c0c4bd65e29a5983361bbf478ddcc14d9ecd8

address_and_keys_from_seed (aka create_address in previous mymonero-core-js), generate_key_derivation, derive_public_key, derive_subaddress_public_key, and decodeRct