Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding .initRustCrypto() support to Expo (React Native) #4150

Closed
greynewell opened this issue Apr 5, 2024 · 12 comments
Closed

Adding .initRustCrypto() support to Expo (React Native) #4150

greynewell opened this issue Apr 5, 2024 · 12 comments
Labels
T-Other Questions, user support, anything else

Comments

@greynewell
Copy link

Howdy! I've been working to enable initRustCrypto() inside of Expo:
https://github.com/wdym-chat/expo-matrix-js-sdk/issues/5

I was able to sideload WASM support inside React Native using Cawfree's package, but ran into an issue:
cawfree/react-native-webassembly#28

ERROR  Error: Unable to bind Webassembly to React Native JSI., js engine: hermes 
    at ContextNavigator (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:148978:24)
    at ExpoRoot (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:148934:28)
    at App
    at ErrorToastContainer (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:378338:24)
    at ErrorOverlay
    at withDevTools(ErrorOverlay) (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:377872:27)
    at RCTView
    at View (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:40346:43)
    at RCTView
    at View (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:40346:43)
    at AppContainer (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:40157:36)
    at main(RootComponent) (http://<MY_IP:PORT>/node_modules/expo-router/entry.bundle//&platform=ios&dev=true&hot=false&lazy=true&transform.engine=hermes&transform.bytecode=true&transform.routerRoot=app:123933:28)

I wanted to ask, has anyone here successfully initialized Rust crypto (or even the legacy crypto) in React Native, and if so, how did you achieve that?

I've been researching this issue pretty hard, and the working solutions out there seem to rely on extremely dated libs/runtimes and to be exclusive of Expo, so any suggestions would be welcomed.

@greynewell
Copy link
Author

Interestingly, I seem to run into the same roadblock with the legacy initCrypto() after polyfilling crypto, fs, and path with Browserify:

Will try uninstalling cawfree's package to see if I can unblock the legacy path another way.

@greynewell
Copy link
Author

Sadly, it appears WebAssembly support is required to load even the legacy Olm based crypto:

 DEBUG  Crypto: Starting up crypto store...
 DEBUG  Crypto: initialising roomlist...
 DEBUG  Crypto: initialising crypto object...
 DEBUG  Crypto: initialising Olm...
 WARN  Aborted(no native wasm support detected)
 ERROR  no native wasm support detected

Will keep digging to see if I can find a workaround.

@t3chguy
Copy link
Member

t3chguy commented Apr 8, 2024

Sadly, it appears WebAssembly support is required to load even the legacy Olm based crypto:

Yes, Olm is a C++ library so cannot be loaded without WASM

@Johennes
Copy link
Contributor

@greynewell I haven't yet attempted this myself but what if you connected olm on the native side? https://github.com/jitsi/react-native-olm appears to go down that route.

@Johennes
Copy link
Contributor

Johennes commented Apr 16, 2024

I was able to get https://github.com/jitsi/react-native-olm to compile and run. It only includes the Account and Session classes though and merely a subset of the available methods on either. We'd have to add the remaining methods and classes to match https://gitlab.matrix.org/matrix-org/olm/-/blob/master/javascript/index.d.ts. It's not exactly little work but then again it's probably a matter of diligence given that things should largely follow what already exists in the library.

Additionally to the above, the library also needs fixes for both platforms to work with recent React Native versions. I put in issues with details upstream.

@Johennes
Copy link
Contributor

Sadly, it appears WebAssembly support is required to load even the legacy Olm based crypto:

Yes, Olm is a C++ library so cannot be loaded without WASM

Actually, seems like there is a legacy-legacy version of Olm that does not depend on WASM.

  • Using olm/olm.js will use the WebAssembly version of the library. For
    environments that do not support WebAssembly, use olm/olm_legacy.js.

https://gitlab.matrix.org/matrix-org/olm/-/blob/master/CHANGELOG.rst#L278-279

@Johennes
Copy link
Contributor

Confirming that decryption works in React Native without WASM by using olm_legacy and https://github.com/margelo/react-native-quick-crypto. 🤩

@greynewell
Copy link
Author

@Johennes Care to drop a working example?

@Johennes
Copy link
Contributor

Johennes commented Apr 17, 2024

I only have this set up in a private app at the moment, unfortunately, and only in PoC form. I'm also not using Expo, so I'm not sure if what I've done transfers easily. But, for what it's worth, here are the steps I took:

  • Add @matrix-org/olm & react-native-quick-crypto as a dependency
  • Map crypto imports to react-native-quick-crypto via metro.config.js
resolveRequest: (context, moduleName, platform) => {
  // Map crypto imports from olm to react-native-quick-crypto
  if (moduleName === 'crypto') {
    return context.resolveRequest(context, 'react-native-quick-crypto', platform);
  }
}
  • Import react-native-quick-crypto and set Olm global In index.js
import 'react-native-quick-crypto';
global.Olm = require('@matrix-org/olm/olm_legacy'); <<< Note how this is using olm_legacy
  • Call client.initCrypto(); inbetween createClient and client.startClient
  • Try using client.decryptEventIfNeeded(event) to decrypt new events

There is more work needed to create a crypto store that persists keys and such across app relaunches (the ones that ship with matrix-js-sdk don't work in React Native). But at least, as a puncture, I was able to decrypt events this way.

@MidhunSureshR MidhunSureshR added the T-Other Questions, user support, anything else label Apr 30, 2024
@richvdh
Copy link
Member

richvdh commented May 16, 2024

Unfortunately, it's unlikely we'll support the Rust crypto library in an environment that doesn't support WASM. [I don't know if building it as a native node module or something might work in future, but that's not likely to happen in the short term.]

You might be able to get the legacy library working for now, but we'll be removing it soon (element-hq/element-web#26922). element-hq/element-web#26922 (comment) discusses ways we might be able to improve this in future.

@richvdh richvdh closed this as completed May 16, 2024
@nitesh-habilelabs
Copy link

nitesh-habilelabs commented Jun 13, 2024

I only have this set up in a private app at the moment, unfortunately, and only in PoC form. I'm also not using Expo, so I'm not sure if what I've done transfers easily. But, for what it's worth, here are the steps I took:

  • Add @matrix-org/olm & react-native-quick-crypto as a dependency
  • Map crypto imports to react-native-quick-crypto via metro.config.js
resolveRequest: (context, moduleName, platform) => {
  // Map crypto imports from olm to react-native-quick-crypto
  if (moduleName === 'crypto') {
    return context.resolveRequest(context, 'react-native-quick-crypto', platform);
  }
}
  • Import react-native-quick-crypto and set Olm global In index.js
import 'react-native-quick-crypto';
global.Olm = require('@matrix-org/olm/olm_legacy'); <<< Note how this is using olm_legacy
  • Call client.initCrypto(); inbetween createClient and client.startClient
  • Try using client.decryptEventIfNeeded(event) to decrypt new events

There is more work needed to create a crypto store that persists keys and such across app relaunches (the ones that ship with matrix-js-sdk don't work in React Native). But at least, as a puncture, I was able to decrypt events this way.

hi , can you please mention specific version of react-native-quick-crypto which you used. i am also trying to integrate matrix in my react native app. and i am getting error that TypeError: Cannot read property 'getRandomValues' of undefined if i don’t import it in index.js or anywhere. and if i import it then i get the error TypeError: Cannot read property 'slice' of undefined, js engine: hermes and i am unable to solve it. thank you in advance.

My RN Version: 0.72.3
"react-native-quick-crypto": "^0.6.1",
"@matrix-org/olm": "^3.2.15",

@Johennes
Copy link
Contributor

We probably shouldn't be discussing on a closed issue but for lack of a better place and future reference:

0.6.1 should have crypto.getRandomValues so your problem is likely a case of making crypto available to your dependencies. I did both, redirect the crypto import and import react-native-quick-crypto in index.js.

That being said, I have since given up on trying to use matrix-js-sdk with React Native as it kept feeling like an uphill battle. There's nothing wrong with matrix-js-sdk. It's just that RN's environment is peculiar enough that trying to use a non-trivial library that wasn't specifically written for RN can be a royal pain in the ****. The further issues I ran into were that https://github.com/matrix-org/matrix-encrypt-attachment doesn't work with RN out of the box and that react-native-quick-crypto has very limited support for crypto.subtle.

I have started an effort to make matrix-rust-sdk available in RN via a turbo module but it's still very far from being usable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-Other Questions, user support, anything else
Projects
None yet
Development

No branches or pull requests

6 participants