MixinNetwork / libsignal_protocol_dart

Signal Protocol library for Dart/Flutter
https://pub.dev/packages/libsignal_protocol_dart
GNU General Public License v3.0
159 stars 42 forks source link

Fully support DartJS + add overwrite methods to boost web performance #43

Closed lemoony closed 2 years ago

lemoony commented 3 years ago

Fixes the issue discussed in #42

Uses reworked versions of the dependencies ed25519_edwards and x25519 that fully support web without performance losses on mobile or dekstop platforms. I've also created the following pull requests:

Moreover, the changes adds two overwrite methods in order to allow to boost performance on the Web by calling Javascript implementations.

Tougee commented 3 years ago

Hi @lemoony

I am considering if it is necessary to embed js implementation so that this lib can be ready to use right out of the box.

Tougee commented 3 years ago

got a test failed by run

dart run test -p chrome test/fingerprint/numeric_fingerprint_generator_test.dart -N testVectorsVersion1

Tougee commented 3 years ago

got a test failed by run

dart run test -p chrome test/fingerprint/numeric_fingerprint_generator_test.dart -N testVectorsVersion1

I found the cause of this is still the dart2js stuff, and using fixnum can resolve this.

static int byteArray5ToLong(Uint8List bytes, int offset) {
    final v1 = (Number(bytes[offset]) & Number(0xff)) << 32;
    final v2 = (Number(bytes[offset + 1]) & Number(0xff)) << 24;
    final v3 = (Number(bytes[offset + 2]) & Number(0xff)) << 16;
    final v4 = (Number(bytes[offset + 3]) & Number(0xff)) << 8;
    final v5 = Number(bytes[offset + 4]) & Number(0xff);
    return (v1 | v2 | v3 | v4 | v5).intValue;
  }

Would you mind extracting number, int, and int64 code as an independent lib, this would be a handy lib.

lemoony commented 3 years ago

got a test failed by run dart run test -p chrome test/fingerprint/numeric_fingerprint_generator_test.dart -N testVectorsVersion1

I found the cause of this is still the dart2js stuff, and using fixnum can resolve this.

static int byteArray5ToLong(Uint8List bytes, int offset) {
    final v1 = (Number(bytes[offset]) & Number(0xff)) << 32;
    final v2 = (Number(bytes[offset + 1]) & Number(0xff)) << 24;
    final v3 = (Number(bytes[offset + 2]) & Number(0xff)) << 16;
    final v4 = (Number(bytes[offset + 3]) & Number(0xff)) << 8;
    final v5 = Number(bytes[offset + 4]) & Number(0xff);
    return (v1 | v2 | v3 | v4 | v5).intValue;
  }

Would you mind extracting number, int, and int64 code as an independent lib, this would be a handy lib.

Sure, won't get to it today but probably tomorrow.

lemoony commented 3 years ago

@Tougee I've created the library adaptive_number. As far as I can tell, all tests are now running also on Chrome.

lemoony commented 3 years ago

Hi @lemoony

I am considering if it is necessary to embed js implementation so that this lib can be ready to use right out of the box.

Regarding this topic: I don't know if it is possible and/or advisible to ship JS files with dart libraries. So all we could do is to include the js facade... this, however, would force the consumer to use the same JS implementation.

Not totally sure but I think i would prefer to just provide an example setup that supports web (like this one: https://github.com/lemoony/signal_protocol_example_app) + some documentation.

Tougee commented 3 years ago

Regarding this topic: I don't know if it is possible and/or advisible to ship JS files with dart libraries. So all we could do is to include the js facade... this, however, would force the consumer to use the same JS implementation.

Not totally sure but I think i would prefer to just provide an example setup that supports web (like this one: https://github.com/lemoony/signal_protocol_example_app) + some documentation.

What you said makes sense, I'll look at your new improvements first.

lemoony commented 3 years ago

On second thought, I also like the idea of a companion library (e.g., libsignal_protocol_flutter_web) which contains all the required assets and librares to make it run on the web. This would definitely ease web integration for most users, while still allowing to customize it if needed.

Wouldn't be much of work. If you like me to do it, let me know.

Tougee commented 3 years ago

Maybe we moved into a wrong corner, I added benchmarks for curve25519, the results show the processing is fast enough, maybe we can just use the Dart implementation of curver25519.

As you mentioned here https://github.com/MixinNetwork/libsignal_protocol_dart/issues/42#issuecomment-917592018, when I extract https://github.com/lemoony/signal_protocol_example_app/blob/main/lib/main.dart#L61 into a simple test method, and run it with flutter test -d chrome, the current Dart implementation algorithms are as fast as the js implementation, I think there may be some other things that blind us and I am not digging into that yet.

import 'package:flutter_test/flutter_test.dart';
import 'package:signal_protocol_example_app/client.dart';

void main() {
  Stopwatch? _stopwatch;

  void _addMessage(String message) {
    final msg = "$message\t\t${_stopwatch?.elapsed.inSeconds}s";
    print(msg);
  }

  test('test signal', () async {
    _stopwatch = Stopwatch()..start();

    _addMessage('started');
    final aliceClient = Client(address: 'Alice', deviceId: 1);
    final bobClient = Client(address: 'Bob', deviceId: 1);
    _addMessage('created clients');

    await aliceClient.initialize();
    await bobClient.initialize();
    _addMessage('initialized clients');

    await aliceClient.initSession(
      bobClient.address,
      bobClient.generatePreKeyBundle(),
    );
    _addMessage('Alice: Initialized session with Bob');

    await bobClient.initSession(
      aliceClient.address,
      aliceClient.generatePreKeyBundle(),
    );
    _addMessage('Bob: Initialized session with Alice');

    for (var i = 0; i < 100; i++) {
      final senderClient = i % 2 == 0 ? aliceClient : bobClient;
      final receiverClient = i % 2 == 0 ? bobClient : aliceClient;
      final msg = i % 2 == 0 ? '$i: Hello there' : '$i: Hello back';
      final encrypted = await senderClient.encrypt(receiverClient.address, msg);
      final decrypted = await receiverClient.decrypt(
        senderClient.address,
        encrypted,
      );
      _addMessage(decrypted);
    }

    _stopwatch?.stop();
    print('Took ${_stopwatch?.elapsed}');
  });
}
lemoony commented 3 years ago

Flutter doesn't seem to use a JS runtime when testing via flutter test -d chrome. If you set a breakpoint both in the int and int64 implementation of Number, you will see that it will not use the int64 one. Because of that, the test runs with the performance expected from a mobile platform.

Tougee commented 3 years ago

Hi @lemoony , sorry for the slow response, busy life and work these days, and we're moving into a medium vacation, so I'm leaving a short response to let you know.

Flutter doesn't seem to use a JS runtime when testing via flutter test -d chrome.

This confused me a lot, and that 2 algorithm lib's benchmark should be reconsidered.

Did you hurry to use this lib on web, if yes we can make a solution faster, otherwise we can talk about this later.

lemoony commented 3 years ago

Hi @Tougee , no hurry from my side - i can work with my forks. Just give notice when you want to move forward with this.

Regarding the benchmarks: The dart tests run with -p chrome do use a JS runtime, it's just the flutter command that does not work as expected (as far as i can tell).

crossle commented 2 years ago

@lemoony Can you fix the conlicts?

lemoony commented 2 years ago

Yes, i will get to it the next couple of days!

Ahmadre commented 2 years ago

Yes, i will get to it the next couple of days!

Any news here?

lemoony commented 2 years ago

@Ahmadre Sorry for the slow response - i've resovled the conflicts. Everything still works from my point of view.