Open CMCDragonkai opened 2 years ago
HTTP2 servers are compatible with HTTP1.1 with TLS. The way this works is through ALPN. This is done at the TLS-level. See: https://superuser.com/questions/1659248/how-does-browser-know-which-version-of-http-it-should-use-when-sending-a-request
In Nodejs the HTTP2 module is capable of accepting HTTP1.1 with TLS connections: https://nodejs.org/api/http2.html#alpn-negotiation.
If an HTTP3 server is available, an HTTP2 client would have to be "upgraded" to the HTTP3 protocol. It is not possible for an HTTP2 client to directly contact HTTP3, because it is a UDP port.
That means if we are using tunneling http2 which multiplex our jsonrpc into utp-native. Our server side should still receive requests outside of utp-native as just normal http1.1+TLS or http2 on TCP. In fact this is exactly how our GRPC server does right now, it accepts connections on TCP and through the utp-native proxy tunnel.
Moving this to main Polykey repository now.
While working on #466, I discovered:
As you can see there are some libraries for webcrypto in react native, however they are not fully supported, and some rely on webview bridges. It seems there are 3 possibilities:
In our latest PR #446 we are making use of webcrypto API. However the actual implementation is backed by @peculiar/webcrypto
which is a polyfill. In particular it has a different implementation of the Ed25519 algorithms. This is because neither browser webcrypto nor nodejs have a common implementation of Ed25519 and X25519. Nodejs has its own experimental implementation that is not compatible: https://github.com/PeculiarVentures/webcrypto/issues/55
The polyfill is designed for nodejs, it builds up a webcrypto API based on node's crypto API. This is therefore not going to be useful in the case of react native.
There's an additional library: https://github.com/PeculiarVentures/webcrypto-liner that polyfills browser implementations in the same vein. Again not entirely useful for mobile OS, since we don't work directly in a browser. And electron would use the node polyfill anyway.
The current benchmarks show some significant improvement:
Current performance notes:
- Symmetric operations is 10x improvement
- Random bytes generation is 100x improvement
- Generating root key is 3563x improvement (deterministic is 100x - 400x faster due to pbkdf2 is still slow)
- Asymmetric encryption didn't change much, but the fact that you can now encrypt arbitrary data sizes is significant.
- Asymmetric decryption is is 68x faster
- Asymmetric signing is 300x faster
- Asymmetric verification didn't change much
At the very least we have a situation where we expect there to be a globalThis.crypto
object that facilitates webcrypto API, in TS, this is the Crypto
type. This allows all of our libraries that support webcrypto to leverage that instead of using other crypto APIs, this includes all of the noble libraries and JOSE libraries.
Now as I said before, we still have to deal with mobile OS, and we deal with that in still the 4 ways:
I want to provide some possible avenues of approach for each:
The webview looks unmaintained but it could be done.
What is of interest is the libsodium library. It is claimed that libsodium is meant for cross-platform usage. Look at all the available bindings: https://doc.libsodium.org/bindings_for_other_languages. The fact that there are multiple implementations and the fact that they have been made WASM capable, as well as native node implementations of sodium should meant that libsodium might be exactly what we've been looking for.
Because our libraries still expect a webcrypto API, we may just need to reimplement the webcrypto API using an underlying libsodium library which then means:
globalThis.crypto
Given the current benchmark numbers, we now have a way of comparing if any particular choice will maintain decent performance of our required crypto primitives.
I'd be curious exactly how fast/slow the WASM variants are compared to native code. We're using webcrypto now which I believe ultimately uses node's openssl code which is native, but how much are we losing by using WASM. This allows us to know if it's feasible to use WASM, especially since on ios there's no JIT.
In order to use any of the WASM based libraries, we have to have top level await. This is because the wasm libraries all require asynchronous initialisation.
Without a top level await, we would end up having to export promises.
Now top level await is only available as part of the greater migration towards EcmaScript modules over CJS modules.
The transition to ESM is going to be tricky, but this https://www.typescriptlang.org/docs/handbook/esm-node.html provides more information on how to do this.
We have an issue tracking this in https://github.com/MatrixAI/TypeScript-Demo-Lib/issues/32.
Since we are still inter-operating with old CJS modules, most likely this means we are using NodeNext
for both moduleResolution
and module
.
However our ts-node
doesn't yet support ESM yet, so until we also change that over if they finally acquire support for this. See: https://github.com/TypeStrong/ts-node/issues/1007
At any case, since WASM is unlikely to be ready for mobile deployment, we're likely to not bother with the WASM variants of libsodium anyway.
I've moved to using libsodium in https://github.com/MatrixAI/Polykey/pull/446#issuecomment-1271185189. However there are 2 places that still require webcrypto. Future work should work on these systems to remove the reliance on webcrypto.
In this case, all crypto related functionality will be on top of libsodium.
A few other things:
Some things to factor out:
ws
node package, but later convert it to a runtime-less library like quicheIf we want to centralise to particular TLS implementation, we might even need a separate http related implementation... or at least redirect its usage of TLS by plugging our own TLS to mock over the TLS used by http/http2 module?
One could potentially override nodejs with boringssl alternative, then force the usage of that in js-quic. Will need to dive deeper into how nodejs is compiled to achieve this.
Specification
We want PK to be truly cross-platform. But PK is very complex, involving many components are not truly cross-platform. These components include:
Over the development process of PK, we've found many roadblocks to achieve a truly cross-platform PK system. This issue tracks all of these areas, and the progress towards more cross-platform deployment necessitating multiple new solutions in multiple areas.
This issue is likely to be a moving target, since cross platform development solutions keeps evolving.
Additional context
Tasks