From f0aa848189d4a6e05cb19837d3352dba69b4a6cb Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 1 Aug 2023 14:13:33 -0600 Subject: [PATCH 01/49] add serai submodule --- .gitmodules | 3 +++ src/serai | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 src/serai diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..01500a7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/serai"] + path = src/serai + url = https://github.com/kayabaNerve/serai diff --git a/src/serai b/src/serai new file mode 160000 index 0000000..5d4632b --- /dev/null +++ b/src/serai @@ -0,0 +1 @@ +Subproject commit 5d4632bace0df2c140a1bbbb2ba487de967fa8f3 From 734658e8db7f01a8c39fd848d03ee96945d07333 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 1 Aug 2023 16:50:23 -0600 Subject: [PATCH 02/49] WIP test build scripts --- scripts/linux/build_all.sh | 17 +++++++++++++++++ scripts/linux/regen_bindings.sh | 5 +++++ 2 files changed, 22 insertions(+) create mode 100755 scripts/linux/build_all.sh create mode 100755 scripts/linux/regen_bindings.sh diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh new file mode 100755 index 0000000..6403307 --- /dev/null +++ b/scripts/linux/build_all.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +ROOT_DIR="$(pwd)/../.." + +mkdir -p build + + +cd "$ROOT_DIR"/src/serai/hrf || exit +if [ "$IS_ARM" = true ] ; then + echo "Building arm frostdart" + cargo build --target aarch64-unknown-linux-gnu --release --lib + cp ../target/aarch64-unknown-linux-gnu/release/libfrostdart.so "$ROOT_DIR"/scripts/linux/build/frostdart.so +else + echo "Building x86_64 frostdart" + cargo build --target x86_64-unknown-linux-gnu --release --lib + cp ../target/x86_64-unknown-linux-gnu/release/libfrostdart.so "$ROOT_DIR"/scripts/linux/build/frostdart.so +fi \ No newline at end of file diff --git a/scripts/linux/regen_bindings.sh b/scripts/linux/regen_bindings.sh new file mode 100755 index 0000000..d52b878 --- /dev/null +++ b/scripts/linux/regen_bindings.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cd ../.. + +dart run ffigen --config ffigen.yaml \ No newline at end of file From 3a61bae8c74b0cfb3621a4b39be3378df4fa6de5 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 1 Aug 2023 17:07:44 -0600 Subject: [PATCH 03/49] ffigen yaml --- ffigen.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ffigen.yaml b/ffigen.yaml index cb2140b..27f6d9f 100644 --- a/ffigen.yaml +++ b/ffigen.yaml @@ -7,9 +7,9 @@ description: | output: 'lib/frostdart_bindings_generated.dart' headers: entry-points: - - 'src/frostdart.h' + - 'src/serai/hrf/header.h' include-directives: - - 'src/frostdart.h' + - 'src/serai/hrf/header.h' preamble: | // ignore_for_file: always_specify_types // ignore_for_file: camel_case_types From 9996b175673fc6c16286a9887e4a146709832f76 Mon Sep 17 00:00:00 2001 From: Josh Babb Date: Wed, 2 Aug 2023 11:40:30 -0500 Subject: [PATCH 04/49] update serai submodule to 1674b217 Various tweaks to bindings --- src/serai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serai b/src/serai index 5d4632b..1674b21 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit 5d4632bace0df2c140a1bbbb2ba487de967fa8f3 +Subproject commit 1674b21712a87297bf30c291163a21e6158212f7 From a71f1259d45d36e29ce393cd58000744031e7b7c Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 2 Aug 2023 11:28:49 -0600 Subject: [PATCH 05/49] somewhat "working" linux build --- example/lib/main.dart | 33 +- example/pubspec.lock | 8 + lib/frostdart.dart | 149 +--- lib/frostdart_bindings_generated.dart | 850 ++++++++++++++++++++- linux/CMakeLists.txt | 147 +++- linux/frostdart_plugin.cc | 70 ++ linux/include/frostdart/frostdart_plugin.h | 26 + pubspec.yaml | 2 +- scripts/linux/build_all.sh | 5 +- src/CMakeLists.txt | 154 +++- src/frostdart.c | 23 - src/frostdart.h | 30 - 12 files changed, 1265 insertions(+), 232 deletions(-) create mode 100644 linux/frostdart_plugin.cc create mode 100644 linux/include/frostdart/frostdart_plugin.h delete mode 100644 src/frostdart.c delete mode 100644 src/frostdart.h diff --git a/example/lib/main.dart b/example/lib/main.dart index acb94df..7c18c59 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; -import 'dart:async'; - import 'package:frostdart/frostdart.dart' as frostdart; +import 'package:frostdart/frostdart_bindings_generated.dart'; void main() { runApp(const MyApp()); @@ -15,14 +14,19 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - late int sumResult; - late Future sumAsyncResult; + late CResult_MultisigConfigRes sumResult; + + String name = "REKT"; @override void initState() { super.initState(); - sumResult = frostdart.sum(1, 2); - sumAsyncResult = frostdart.sumAsync(3, 4); + sumResult = frostdart.newMultisigConfig( + name: "Name AAAAAA", + threshold: 3, + participants: ["jimmy", "john", "toby"]); + + // name = frostdart.multisigName(configRes: sumResult.value.ref); } @override @@ -47,22 +51,15 @@ class _MyAppState extends State { ), spacerSmall, Text( - 'sum(1, 2) = $sumResult', + 'Type of result: ${sumResult.runtimeType}', style: textStyle, textAlign: TextAlign.center, ), spacerSmall, - FutureBuilder( - future: sumAsyncResult, - builder: (BuildContext context, AsyncSnapshot value) { - final displayValue = - (value.hasData) ? value.data : 'loading'; - return Text( - 'await sumAsync(3, 4) = $displayValue', - style: textStyle, - textAlign: TextAlign.center, - ); - }, + Text( + 'name: $name', + style: textStyle, + textAlign: TextAlign.center, ), ], ), diff --git a/example/pubspec.lock b/example/pubspec.lock index 7725cd4..d8c9eef 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -57,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" flutter: dependency: "direct main" description: flutter diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 873f126..cebefca 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -1,50 +1,21 @@ - -import 'dart:async'; -import 'dart:ffi'; +import 'dart:ffi' as ffi; import 'dart:io'; -import 'dart:isolate'; - -import 'frostdart_bindings_generated.dart'; -/// A very short-lived native function. -/// -/// For very short-lived functions, it is fine to call them on the main isolate. -/// They will block the Dart execution while running the native function, so -/// only do this for native functions which are guaranteed to be short-lived. -int sum(int a, int b) => _bindings.sum(a, b); - -/// A longer lived native function, which occupies the thread calling it. -/// -/// Do not call these kind of native functions in the main isolate. They will -/// block Dart execution. This will cause dropped frames in Flutter applications. -/// Instead, call these native functions on a separate isolate. -/// -/// Modify this to suit your own use case. Example use cases: -/// -/// 1. Reuse a single isolate for various different kinds of requests. -/// 2. Use multiple helper isolates for parallel execution. -Future sumAsync(int a, int b) async { - final SendPort helperIsolateSendPort = await _helperIsolateSendPort; - final int requestId = _nextSumRequestId++; - final _SumRequest request = _SumRequest(requestId, a, b); - final Completer completer = Completer(); - _sumRequests[requestId] = completer; - helperIsolateSendPort.send(request); - return completer.future; -} +import 'package:ffi/ffi.dart'; +import 'package:frostdart/frostdart_bindings_generated.dart'; const String _libName = 'frostdart'; /// The dynamic library in which the symbols for [FrostdartBindings] can be found. -final DynamicLibrary _dylib = () { +final ffi.DynamicLibrary _dylib = () { if (Platform.isMacOS || Platform.isIOS) { - return DynamicLibrary.open('$_libName.framework/$_libName'); + return ffi.DynamicLibrary.open('$_libName.framework/$_libName'); } if (Platform.isAndroid || Platform.isLinux) { - return DynamicLibrary.open('lib$_libName.so'); + return ffi.DynamicLibrary.open('$_libName.so'); } if (Platform.isWindows) { - return DynamicLibrary.open('$_libName.dll'); + return ffi.DynamicLibrary.open('$_libName.dll'); } throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); }(); @@ -52,80 +23,40 @@ final DynamicLibrary _dylib = () { /// The bindings to the native functions in [_dylib]. final FrostdartBindings _bindings = FrostdartBindings(_dylib); - -/// A request to compute `sum`. -/// -/// Typically sent from one isolate to another. -class _SumRequest { - final int id; - final int a; - final int b; - - const _SumRequest(this.id, this.a, this.b); +CResult_MultisigConfigRes newMultisigConfig({ + required String name, + required int threshold, + required List participants, +}) { + ffi.Pointer multisigName = name.toNativeUtf8().cast(); + + final joined = participants.join(); + ffi.Pointer parts = joined.toNativeUtf8().cast(); + + ffi.Pointer participantsPointer = calloc(); + participantsPointer.ref.ptr = parts; + participantsPointer.ref.len = joined.length; + + final result = _bindings.new_multisig_config( + multisigName, + name.length, + threshold, + participantsPointer, + participants.length, + ); + + calloc.free(multisigName); + calloc.free(parts); + calloc.free(participantsPointer); + + return result; } -/// A response with the result of `sum`. -/// -/// Typically sent from one isolate to another. -class _SumResponse { - final int id; - final int result; - - const _SumResponse(this.id, this.result); -} +String multisigName({required MultisigConfigRes configRes}) { + final result = _bindings.multisig_name(configRes.config); -/// Counter to identify [_SumRequest]s and [_SumResponse]s. -int _nextSumRequestId = 0; + final bytes = result.ptr.asTypedList(result.len); + final String name = String.fromCharCodes(bytes); -/// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request. -final Map> _sumRequests = >{}; - -/// The SendPort belonging to the helper isolate. -Future _helperIsolateSendPort = () async { - // The helper isolate is going to send us back a SendPort, which we want to - // wait for. - final Completer completer = Completer(); - - // Receive port on the main isolate to receive messages from the helper. - // We receive two types of messages: - // 1. A port to send messages on. - // 2. Responses to requests we sent. - final ReceivePort receivePort = ReceivePort() - ..listen((dynamic data) { - if (data is SendPort) { - // The helper isolate sent us the port on which we can sent it requests. - completer.complete(data); - return; - } - if (data is _SumResponse) { - // The helper isolate sent us a response to a request we sent. - final Completer completer = _sumRequests[data.id]!; - _sumRequests.remove(data.id); - completer.complete(data.result); - return; - } - throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); - }); - - // Start the helper isolate. - await Isolate.spawn((SendPort sendPort) async { - final ReceivePort helperReceivePort = ReceivePort() - ..listen((dynamic data) { - // On the helper isolate listen to requests and respond to them. - if (data is _SumRequest) { - final int result = _bindings.sum_long_running(data.a, data.b); - final _SumResponse response = _SumResponse(data.id, result); - sendPort.send(response); - return; - } - throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); - }); - - // Send the port to the main isolate on which we can receive requests. - sendPort.send(helperReceivePort.sendPort); - }, receivePort.sendPort); - - // Wait until the helper isolate has sent us back the SendPort on which we - // can start sending requests. - return completer.future; -}(); + return name; +} diff --git a/lib/frostdart_bindings_generated.dart b/lib/frostdart_bindings_generated.dart index 4a3bebe..e8e5d4b 100644 --- a/lib/frostdart_bindings_generated.dart +++ b/lib/frostdart_bindings_generated.dart @@ -5,6 +5,7 @@ // AUTO GENERATED FILE, DO NOT EDIT. // // Generated by `package:ffigen`. +// ignore_for_file: type=lint import 'dart:ffi' as ffi; /// Bindings for `src/frostdart.h`. @@ -26,44 +27,831 @@ class FrostdartBindings { lookup) : _lookup = lookup; - /// A very short-lived native function. - /// - /// For very short-lived functions, it is fine to call them on the main isolate. - /// They will block the Dart execution while running the native function, so - /// only do this for native functions which are guaranteed to be short-lived. - int sum( - int a, - int b, + void free_owned_string( + OwnedString self, ) { - return _sum( - a, - b, + return _free_owned_string( + self, ); } - late final _sumPtr = - _lookup>( - 'sum'); - late final _sum = _sumPtr.asFunction(); + late final _free_owned_stringPtr = + _lookup>( + 'free_owned_string'); + late final _free_owned_string = + _free_owned_stringPtr.asFunction(); - /// A longer lived native function, which occupies the thread calling it. - /// - /// Do not call these kind of native functions in the main isolate. They will - /// block Dart execution. This will cause dropped frames in Flutter applications. - /// Instead, call these native functions on a separate isolate. - int sum_long_running( - int a, - int b, + StringView multisig_name( + ffi.Pointer self, ) { - return _sum_long_running( - a, - b, + return _multisig_name( + self, ); } - late final _sum_long_runningPtr = - _lookup>( - 'sum_long_running'); - late final _sum_long_running = - _sum_long_runningPtr.asFunction(); + late final _multisig_namePtr = _lookup< + ffi.NativeFunction)>>( + 'multisig_name'); + late final _multisig_name = _multisig_namePtr + .asFunction)>(); + + int multisig_threshold( + ffi.Pointer self, + ) { + return _multisig_threshold( + self, + ); + } + + late final _multisig_thresholdPtr = _lookup< + ffi.NativeFunction)>>( + 'multisig_threshold'); + late final _multisig_threshold = _multisig_thresholdPtr + .asFunction)>(); + + int multisig_participants( + ffi.Pointer self, + ) { + return _multisig_participants( + self, + ); + } + + late final _multisig_participantsPtr = _lookup< + ffi.NativeFunction< + ffi.UintPtr Function( + ffi.Pointer)>>('multisig_participants'); + late final _multisig_participants = _multisig_participantsPtr + .asFunction)>(); + + StringView multisig_participant( + ffi.Pointer self, + int i, + ) { + return _multisig_participant( + self, + i, + ); + } + + late final _multisig_participantPtr = _lookup< + ffi.NativeFunction< + StringView Function(ffi.Pointer, + ffi.UintPtr)>>('multisig_participant'); + late final _multisig_participant = _multisig_participantPtr + .asFunction, int)>(); + + ffi.Pointer multisig_salt( + ffi.Pointer self, + ) { + return _multisig_salt( + self, + ); + } + + late final _multisig_saltPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('multisig_salt'); + late final _multisig_salt = _multisig_saltPtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); + + ffi.Pointer multisig_config( + ffi.Pointer self, + ) { + return _multisig_config( + self, + ); + } + + late final _multisig_configPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('multisig_config'); + late final _multisig_config = _multisig_configPtr.asFunction< + ffi.Pointer Function( + ffi.Pointer)>(); + + StringView multisig_my_name( + ffi.Pointer self, + ) { + return _multisig_my_name( + self, + ); + } + + late final _multisig_my_namePtr = _lookup< + ffi.NativeFunction< + StringView Function( + ffi.Pointer)>>('multisig_my_name'); + late final _multisig_my_name = _multisig_my_namePtr + .asFunction)>(); + + CResult_MultisigConfigRes new_multisig_config( + ffi.Pointer multisig_name, + int multisig_name_len, + int threshold, + ffi.Pointer participants, + int participants_len, + ) { + return _new_multisig_config( + multisig_name, + multisig_name_len, + threshold, + participants, + participants_len, + ); + } + + late final _new_multisig_configPtr = _lookup< + ffi.NativeFunction< + CResult_MultisigConfigRes Function( + ffi.Pointer, + ffi.UintPtr, + ffi.Uint16, + ffi.Pointer, + ffi.Uint16)>>('new_multisig_config'); + late final _new_multisig_config = _new_multisig_configPtr.asFunction< + CResult_MultisigConfigRes Function( + ffi.Pointer, int, int, ffi.Pointer, int)>(); + + CResult_MultisigConfig decode_multisig_config( + StringView config, + ) { + return _decode_multisig_config( + config, + ); + } + + late final _decode_multisig_configPtr = + _lookup>( + 'decode_multisig_config'); + late final _decode_multisig_config = _decode_multisig_configPtr + .asFunction(); + + CResult_StartKeyGenRes start_key_gen( + ffi.Pointer config, + StringView my_name, + int language, + ) { + return _start_key_gen( + config, + my_name, + language, + ); + } + + late final _start_key_genPtr = _lookup< + ffi.NativeFunction< + CResult_StartKeyGenRes Function(ffi.Pointer, + StringView, ffi.Uint16)>>('start_key_gen'); + late final _start_key_gen = _start_key_genPtr.asFunction< + CResult_StartKeyGenRes Function( + ffi.Pointer, StringView, int)>(); + + CResult_SecretSharesRes get_secret_shares( + ffi.Pointer config, + int language, + StringView seed, + ffi.Pointer machine, + ffi.Pointer commitments, + int commitments_len, + ) { + return _get_secret_shares( + config, + language, + seed, + machine, + commitments, + commitments_len, + ); + } + + late final _get_secret_sharesPtr = _lookup< + ffi.NativeFunction< + CResult_SecretSharesRes Function( + ffi.Pointer, + ffi.Uint16, + StringView, + ffi.Pointer, + ffi.Pointer, + ffi.UintPtr)>>('get_secret_shares'); + late final _get_secret_shares = _get_secret_sharesPtr.asFunction< + CResult_SecretSharesRes Function( + ffi.Pointer, + int, + StringView, + ffi.Pointer, + ffi.Pointer, + int)>(); + + CResult_KeyGenRes complete_key_gen( + ffi.Pointer config, + SecretSharesRes machine_and_commitments, + ffi.Pointer shares, + int shares_len, + ) { + return _complete_key_gen( + config, + machine_and_commitments, + shares, + shares_len, + ); + } + + late final _complete_key_genPtr = _lookup< + ffi.NativeFunction< + CResult_KeyGenRes Function( + ffi.Pointer, + SecretSharesRes, + ffi.Pointer, + ffi.UintPtr)>>('complete_key_gen'); + late final _complete_key_gen = _complete_key_genPtr.asFunction< + CResult_KeyGenRes Function(ffi.Pointer, + SecretSharesRes, ffi.Pointer, int)>(); + + OwnedString serialize_keys( + ffi.Pointer keys, + ) { + return _serialize_keys( + keys, + ); + } + + late final _serialize_keysPtr = _lookup< + ffi.NativeFunction< + OwnedString Function( + ffi.Pointer)>>('serialize_keys'); + late final _serialize_keys = _serialize_keysPtr + .asFunction)>(); + + CResult_ThresholdKeysWrapper deserialize_keys( + StringView keys, + ) { + return _deserialize_keys( + keys, + ); + } + + late final _deserialize_keysPtr = _lookup< + ffi.NativeFunction< + CResult_ThresholdKeysWrapper Function( + StringView)>>('deserialize_keys'); + late final _deserialize_keys = _deserialize_keysPtr + .asFunction(); + + ffi.Pointer output_hash( + ffi.Pointer self, + ) { + return _output_hash( + self, + ); + } + + late final _output_hashPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('output_hash'); + late final _output_hash = _output_hashPtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); + + int output_vout( + ffi.Pointer self, + ) { + return _output_vout( + self, + ); + } + + late final _output_voutPtr = _lookup< + ffi.NativeFunction< + ffi.Uint32 Function( + ffi.Pointer)>>('output_vout'); + late final _output_vout = _output_voutPtr + .asFunction)>(); + + int output_value( + ffi.Pointer self, + ) { + return _output_value( + self, + ); + } + + late final _output_valuePtr = _lookup< + ffi.NativeFunction< + ffi.Uint64 Function( + ffi.Pointer)>>('output_value'); + late final _output_value = _output_valuePtr + .asFunction)>(); + + int output_script_pubkey_len( + ffi.Pointer self, + ) { + return _output_script_pubkey_len( + self, + ); + } + + late final _output_script_pubkey_lenPtr = _lookup< + ffi.NativeFunction< + ffi.UintPtr Function( + ffi.Pointer)>>('output_script_pubkey_len'); + late final _output_script_pubkey_len = _output_script_pubkey_lenPtr + .asFunction)>(); + + ffi.Pointer output_script_pubkey( + ffi.Pointer self, + ) { + return _output_script_pubkey( + self, + ); + } + + late final _output_script_pubkeyPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('output_script_pubkey'); + late final _output_script_pubkey = _output_script_pubkeyPtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); + + int sign_inputs( + ffi.Pointer self, + ) { + return _sign_inputs( + self, + ); + } + + late final _sign_inputsPtr = _lookup< + ffi.NativeFunction)>>( + 'sign_inputs'); + late final _sign_inputs = + _sign_inputsPtr.asFunction)>(); + + ffi.Pointer> sign_input( + ffi.Pointer self, + int i, + ) { + return _sign_input( + self, + i, + ); + } + + late final _sign_inputPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer> Function( + ffi.Pointer, ffi.UintPtr)>>('sign_input'); + late final _sign_input = _sign_inputPtr.asFunction< + ffi.Pointer> Function( + ffi.Pointer, int)>(); + + int sign_payments( + ffi.Pointer self, + ) { + return _sign_payments( + self, + ); + } + + late final _sign_paymentsPtr = _lookup< + ffi.NativeFunction)>>( + 'sign_payments'); + late final _sign_payments = + _sign_paymentsPtr.asFunction)>(); + + StringView sign_payment_address( + ffi.Pointer self, + int i, + ) { + return _sign_payment_address( + self, + i, + ); + } + + late final _sign_payment_addressPtr = _lookup< + ffi.NativeFunction< + StringView Function( + ffi.Pointer, ffi.UintPtr)>>('sign_payment_address'); + late final _sign_payment_address = _sign_payment_addressPtr + .asFunction, int)>(); + + int sign_payment_amount( + ffi.Pointer self, + int i, + ) { + return _sign_payment_amount( + self, + i, + ); + } + + late final _sign_payment_amountPtr = _lookup< + ffi.NativeFunction< + ffi.Uint64 Function( + ffi.Pointer, ffi.UintPtr)>>('sign_payment_amount'); + late final _sign_payment_amount = _sign_payment_amountPtr + .asFunction, int)>(); + + StringView sign_change( + ffi.Pointer self, + ) { + return _sign_change( + self, + ); + } + + late final _sign_changePtr = + _lookup)>>( + 'sign_change'); + late final _sign_change = _sign_changePtr + .asFunction)>(); + + int sign_fee_per_weight( + ffi.Pointer self, + ) { + return _sign_fee_per_weight( + self, + ); + } + + late final _sign_fee_per_weightPtr = + _lookup)>>( + 'sign_fee_per_weight'); + late final _sign_fee_per_weight = _sign_fee_per_weightPtr + .asFunction)>(); + + CResult_SignConfigRes new_sign_config( + int network, + ffi.Pointer outputs, + int outputs_len, + int payments, + ffi.Pointer payment_addresses, + ffi.Pointer payment_amounts, + StringView change, + int fee_per_weight, + ) { + return _new_sign_config( + network, + outputs, + outputs_len, + payments, + payment_addresses, + payment_amounts, + change, + fee_per_weight, + ); + } + + late final _new_sign_configPtr = _lookup< + ffi.NativeFunction< + CResult_SignConfigRes Function( + ffi.Int32, + ffi.Pointer, + ffi.UintPtr, + ffi.UintPtr, + ffi.Pointer, + ffi.Pointer, + StringView, + ffi.Uint64)>>('new_sign_config'); + late final _new_sign_config = _new_sign_configPtr.asFunction< + CResult_SignConfigRes Function(int, ffi.Pointer, int, int, + ffi.Pointer, ffi.Pointer, StringView, int)>(); + + CResult_SignConfig decode_sign_config( + int network, + StringView encoded, + ) { + return _decode_sign_config( + network, + encoded, + ); + } + + late final _decode_sign_configPtr = _lookup< + ffi.NativeFunction< + CResult_SignConfig Function( + ffi.Int32, StringView)>>('decode_sign_config'); + late final _decode_sign_config = _decode_sign_configPtr + .asFunction(); + + CResult_AttemptSignRes attempt_sign( + ffi.Pointer keys, + ffi.Pointer> config, + ) { + return _attempt_sign( + keys, + config, + ); + } + + late final _attempt_signPtr = _lookup< + ffi.NativeFunction< + CResult_AttemptSignRes Function(ffi.Pointer, + ffi.Pointer>)>>('attempt_sign'); + late final _attempt_sign = _attempt_signPtr.asFunction< + CResult_AttemptSignRes Function(ffi.Pointer, + ffi.Pointer>)>(); + + CResult_ContinueSignRes continue_sign( + ffi.Pointer machine, + ffi.Pointer preprocesses, + int preprocesses_len, + ) { + return _continue_sign( + machine, + preprocesses, + preprocesses_len, + ); + } + + late final _continue_signPtr = _lookup< + ffi.NativeFunction< + CResult_ContinueSignRes Function( + ffi.Pointer, + ffi.Pointer, + ffi.UintPtr)>>('continue_sign'); + late final _continue_sign = _continue_signPtr.asFunction< + CResult_ContinueSignRes Function( + ffi.Pointer, + ffi.Pointer, + int)>(); + + CResult_OwnedString complete_sign( + ffi.Pointer machine, + ffi.Pointer shares, + int shares_len, + ) { + return _complete_sign( + machine, + shares, + shares_len, + ); + } + + late final _complete_signPtr = _lookup< + ffi.NativeFunction< + CResult_OwnedString Function( + ffi.Pointer, + ffi.Pointer, + ffi.UintPtr)>>('complete_sign'); + late final _complete_sign = _complete_signPtr.asFunction< + CResult_OwnedString Function( + ffi.Pointer, + ffi.Pointer, + int)>(); +} + +abstract class Network { + static const int Mainnet = 0; + static const int Testnet = 1; + static const int Regtest = 2; +} + +final class KeyMachineWrapper extends ffi.Opaque {} + +final class MultisigConfig extends ffi.Opaque {} + +final class OwnedPortableOutput extends ffi.Opaque {} + +final class SecretShareMachineWrapper extends ffi.Opaque {} + +final class SignConfig extends ffi.Opaque {} + +final class RustString extends ffi.Opaque {} + +final class ThresholdKeysWrapper extends ffi.Opaque {} + +final class TransactionSignMachineWrapper extends ffi.Opaque {} + +final class TransactionSignatureMachineWrapper extends ffi.Opaque {} + +final class Vec_u8 extends ffi.Opaque {} + +final class OwnedString extends ffi.Struct { + external ffi.Pointer str_box; + + external ffi.Pointer ptr; + + @ffi.UintPtr() + external int len; +} + +final class StringView extends ffi.Struct { + external ffi.Pointer ptr; + + @ffi.UintPtr() + external int len; +} + +final class MultisigConfigWithName extends ffi.Struct { + external ffi.Pointer config; + + external ffi.Pointer my_name; +} + +final class MultisigConfigRes extends ffi.Struct { + external ffi.Pointer config; + + external OwnedString encoded; +} + +final class CResult_MultisigConfigRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class CResult_MultisigConfig extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class StartKeyGenRes extends ffi.Struct { + external OwnedString seed; + + external ffi.Pointer config; + + external ffi.Pointer machine; + + external OwnedString commitments; +} + +final class CResult_StartKeyGenRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class SecretSharesRes extends ffi.Struct { + external ffi.Pointer machine; + + external ffi.Pointer internal_commitments; + + external OwnedString shares; +} + +final class CResult_SecretSharesRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class KeyGenRes extends ffi.Struct { + @ffi.Array.multi([32]) + external ffi.Array multisig_id; + + external ffi.Pointer keys; + + external OwnedString recovery; } + +final class CResult_KeyGenRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class CResult_ThresholdKeysWrapper extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class SignConfigRes extends ffi.Struct { + external ffi.Pointer config; + + external OwnedString encoded; +} + +final class CResult_SignConfigRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class PortableOutput extends ffi.Struct { + @ffi.Array.multi([32]) + external ffi.Array hash; + + @ffi.Uint32() + external int vout; + + @ffi.Uint64() + external int value; + + external ffi.Pointer script_pubkey; + + @ffi.UintPtr() + external int script_pubkey_len; +} + +final class CResult_SignConfig extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class AttemptSignRes extends ffi.Struct { + external ffi.Pointer machine; + + external OwnedString preprocess; +} + +final class CResult_AttemptSignRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class ContinueSignRes extends ffi.Struct { + external ffi.Pointer machine; + + external OwnedString preprocess; +} + +final class CResult_ContinueSignRes extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +final class CResult_OwnedString extends ffi.Struct { + external ffi.Pointer value; + + @ffi.Uint16() + external int err; +} + +const int LANGUAGE_ENGLISH = 1; + +const int LANGUAGE_CHINESE_SIMPLIFIED = 2; + +const int LANGUAGE_CHINESE_TRADITIONAL = 3; + +const int LANGUAGE_FRENCH = 4; + +const int LANGUAGE_ITALIAN = 5; + +const int LANGUAGE_JAPANESE = 6; + +const int LANGUAGE_KOREAN = 7; + +const int LANGUAGE_SPANISH = 8; + +const int UNKNOWN_ERROR = 101; + +const int INVALID_ENCODING_ERROR = 102; + +const int INVALID_PARTICIPANT_ERROR = 103; + +const int INVALID_SHARE_ERROR = 104; + +const int ZERO_PARAMETER_ERROR = 201; + +const int INVALID_THRESHOLD_ERROR = 202; + +const int INVALID_NAME_ERROR = 203; + +const int UNKNOWN_LANGUAGE_ERROR = 204; + +const int INVALID_SEED_ERROR = 205; + +const int INVALID_AMOUNT_OF_COMMITMENTS_ERROR = 206; + +const int INVALID_COMMITMENTS_ERROR = 207; + +const int INVALID_AMOUNT_OF_SHARES_ERROR = 208; + +const int INVALID_OUTPUT_ERROR = 301; + +const int INVALID_ADDRESS_ERROR = 302; + +const int INVALID_NETWORK_ERROR = 303; + +const int NO_INPUTS_ERROR = 304; + +const int NO_OUTPUTS_ERROR = 305; + +const int DUST_ERROR = 306; + +const int NOT_ENOUGH_FUNDS_ERROR = 307; + +const int TOO_LARGE_TRANSACTION_ERROR = 308; + +const int WRONG_KEYS_ERROR = 309; + +const int INVALID_PREPROCESS_ERROR = 310; diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 202d94d..2e72324 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,16 +7,147 @@ cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "frostdart") project(${PROJECT_NAME} LANGUAGES CXX) -# Invoke the build for native code shared with the other target platforms. -# This can be changed to accommodate different builds. -add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") +# This value is used when generating builds using this plugin, so it must +# not be changed. +set(PLUGIN_NAME "frostdart_plugin") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Define the plugin library target. Its name must not be changed (see comment +# on PLUGIN_NAME above). +# +# Any new source files that you add to the plugin should be added here. +add_library(${PLUGIN_NAME} SHARED + "frostdart_plugin.cc" + ) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Apply a standard set of build settings that are configured in the +# application-level CMakeLists.txt. This can be removed for plugins that want +# full control over build settings. +apply_standard_settings(${PLUGIN_NAME}) + +# Symbols are hidden by default to reduce the chance of accidental conflicts +# between plugins. This should not be removed; any symbols that should be +# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) + +# Source include directories and library dependencies. Add any plugin-specific +# dependencies here. +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. set(frostdart_bundled_libraries - # Defined in ../src/CMakeLists.txt. - # This can be changed to accommodate different builds. - $ - PARENT_SCOPE -) + "" + PARENT_SCOPE + ) + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" + ) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +#include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +install(FILES "${CMAKE_SOURCE_DIR}/../../scripts/linux/build/frostdart.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/frostdart_plugin.cc b/linux/frostdart_plugin.cc new file mode 100644 index 0000000..0f25d52 --- /dev/null +++ b/linux/frostdart_plugin.cc @@ -0,0 +1,70 @@ +#include "include/frostdart/frostdart_plugin.h" + +#include +#include +#include + +#include + +#define frostdart_PLUGIN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), frostdart_plugin_get_type(), \ + FrostdartPlugin)) + +struct _FrostdartPlugin { + GObject parent_instance; +}; + +G_DEFINE_TYPE(FrostdartPlugin, frostdart_plugin, g_object_get_type()); + +// Called when a method call is received from Flutter. +static void frostdart_plugin_handle_method_call( + FrostdartPlugin* self, + FlMethodCall* method_call) { + g_autoptr(FlMethodResponse) response = nullptr; + + const gchar* method = fl_method_call_get_name(method_call); + + if (strcmp(method, "getPlatformVersion") == 0) { + struct utsname uname_data = {}; + uname(&uname_data); + g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); + g_autoptr(FlValue) result = fl_value_new_string(version); + response = FL_METHOD_RESPONSE(fl_method_success_response_new(result)); + } else { + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + } + + fl_method_call_respond(method_call, response, nullptr); +} + +static void frostdart_plugin_dispose(GObject* object) { + G_OBJECT_CLASS(frostdart_plugin_parent_class)->dispose(object); +} + +static void frostdart_plugin_class_init(FrostdartPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = frostdart_plugin_dispose; +} + +static void frostdart_plugin_init(FrostdartPlugin* self) {} + +static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, + gpointer user_data) { + FrostdartPlugin* plugin = frostdart_PLUGIN(user_data); + frostdart_plugin_handle_method_call(plugin, method_call); +} + +void frostdart_plugin_register_with_registrar(FlPluginRegistrar* registrar) { + FrostdartPlugin* plugin = frostdart_PLUGIN( + g_object_new(frostdart_plugin_get_type(), nullptr)); + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) channel = + fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), + "frostdart", + FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(channel, method_call_cb, + g_object_ref(plugin), + g_object_unref); + + g_object_unref(plugin); +} diff --git a/linux/include/frostdart/frostdart_plugin.h b/linux/include/frostdart/frostdart_plugin.h new file mode 100644 index 0000000..e6d0544 --- /dev/null +++ b/linux/include/frostdart/frostdart_plugin.h @@ -0,0 +1,26 @@ +#ifndef FLUTTER_PLUGIN_FROSTDART_PLUGIN_H_ +#define FLUTTER_PLUGIN_FROSTDART_PLUGIN_H_ + +#include + +G_BEGIN_DECLS + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif + +typedef struct _FrostdartPlugin FrostdartPlugin; +typedef struct { + GObjectClass parent_class; +} FrostdartPluginClass; + +FLUTTER_PLUGIN_EXPORT GType frostdart_plugin_get_type(); + +FLUTTER_PLUGIN_EXPORT void frostdart_plugin_register_with_registrar( + FlPluginRegistrar* registrar); + +G_END_DECLS + +#endif // FLUTTER_PLUGIN_FLUTTER_FROSTDART_PLUGIN_H_ diff --git a/pubspec.yaml b/pubspec.yaml index a417513..163cba7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,12 +8,12 @@ environment: flutter: ">=3.10.0" dependencies: + ffi: ^2.0.1 flutter: sdk: flutter plugin_platform_interface: ^2.0.2 dev_dependencies: - ffi: ^2.0.1 ffigen: ^9.0.1 flutter_test: sdk: flutter diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 6403307..14d31c0 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -4,14 +4,13 @@ ROOT_DIR="$(pwd)/../.." mkdir -p build - cd "$ROOT_DIR"/src/serai/hrf || exit if [ "$IS_ARM" = true ] ; then echo "Building arm frostdart" cargo build --target aarch64-unknown-linux-gnu --release --lib - cp ../target/aarch64-unknown-linux-gnu/release/libfrostdart.so "$ROOT_DIR"/scripts/linux/build/frostdart.so + cp ../target/aarch64-unknown-linux-gnu/release/libhrf_api.so "$ROOT_DIR"/scripts/linux/build/frostdart.so else echo "Building x86_64 frostdart" cargo build --target x86_64-unknown-linux-gnu --release --lib - cp ../target/x86_64-unknown-linux-gnu/release/libfrostdart.so "$ROOT_DIR"/scripts/linux/build/frostdart.so + cp ../target/x86_64-unknown-linux-gnu/release/libhrf_api.so "$ROOT_DIR"/scripts/linux/build/frostdart.so fi \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a6f510..2e72324 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,15 +3,151 @@ # the plugin to fail to compile for some customers of the plugin. cmake_minimum_required(VERSION 3.10) -project(frostdart_library VERSION 0.0.1 LANGUAGES C) +# Project-level configuration. +set(PROJECT_NAME "frostdart") +project(${PROJECT_NAME} LANGUAGES CXX) -add_library(frostdart SHARED - "frostdart.c" -) +# This value is used when generating builds using this plugin, so it must +# not be changed. +set(PLUGIN_NAME "frostdart_plugin") -set_target_properties(frostdart PROPERTIES - PUBLIC_HEADER frostdart.h - OUTPUT_NAME "frostdart" -) +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() -target_compile_definitions(frostdart PUBLIC DART_SHARED_LIB) +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Define the plugin library target. Its name must not be changed (see comment +# on PLUGIN_NAME above). +# +# Any new source files that you add to the plugin should be added here. +add_library(${PLUGIN_NAME} SHARED + "frostdart_plugin.cc" + ) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Apply a standard set of build settings that are configured in the +# application-level CMakeLists.txt. This can be removed for plugins that want +# full control over build settings. +apply_standard_settings(${PLUGIN_NAME}) + +# Symbols are hidden by default to reduce the chance of accidental conflicts +# between plugins. This should not be removed; any symbols that should be +# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) + +# Source include directories and library dependencies. Add any plugin-specific +# dependencies here. +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) + +# List of absolute paths to libraries that should be bundled with the plugin. +# This list could contain prebuilt libraries, or libraries created by an +# external build triggered from this build file. +set(frostdart_bundled_libraries + "" + PARENT_SCOPE + ) + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" + ) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +#include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +install(FILES "${CMAKE_SOURCE_DIR}/../../scripts/linux/build/frostdart.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/src/frostdart.c b/src/frostdart.c deleted file mode 100644 index 7c39e12..0000000 --- a/src/frostdart.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "frostdart.h" - -// A very short-lived native function. -// -// For very short-lived functions, it is fine to call them on the main isolate. -// They will block the Dart execution while running the native function, so -// only do this for native functions which are guaranteed to be short-lived. -FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b) { return a + b; } - -// A longer-lived native function, which occupies the thread calling it. -// -// Do not call these kind of native functions in the main isolate. They will -// block Dart execution. This will cause dropped frames in Flutter applications. -// Instead, call these native functions on a separate isolate. -FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b) { - // Simulate work. -#if _WIN32 - Sleep(5000); -#else - usleep(5000 * 1000); -#endif - return a + b; -} diff --git a/src/frostdart.h b/src/frostdart.h deleted file mode 100644 index 084c642..0000000 --- a/src/frostdart.h +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -#if _WIN32 -#include -#else -#include -#include -#endif - -#if _WIN32 -#define FFI_PLUGIN_EXPORT __declspec(dllexport) -#else -#define FFI_PLUGIN_EXPORT -#endif - -// A very short-lived native function. -// -// For very short-lived functions, it is fine to call them on the main isolate. -// They will block the Dart execution while running the native function, so -// only do this for native functions which are guaranteed to be short-lived. -FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b); - -// A longer lived native function, which occupies the thread calling it. -// -// Do not call these kind of native functions in the main isolate. They will -// block Dart execution. This will cause dropped frames in Flutter applications. -// Instead, call these native functions on a separate isolate. -FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b); From 203332efd0f049ef0e69d7590e8390bb037ff2a2 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 2 Aug 2023 11:40:14 -0600 Subject: [PATCH 06/49] "fix" example cmakelist --- example/linux/CMakeLists.txt | 72 +++++++++++++----------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/example/linux/CMakeLists.txt b/example/linux/CMakeLists.txt index f326f18..e5f7c36 100644 --- a/example/linux/CMakeLists.txt +++ b/example/linux/CMakeLists.txt @@ -1,19 +1,11 @@ -# Project-level configuration. cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. set(BINARY_NAME "frostdart_example") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.example.frostdart") -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. cmake_policy(SET CMP0063 NEW) -# Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. @@ -26,19 +18,15 @@ if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() -# Define build configuration options. +# Configure build options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) + STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") + "Debug" "Profile" "Release") endif() # Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) @@ -46,8 +34,9 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() -# Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. @@ -56,36 +45,24 @@ pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. +# Application build add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + ) apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) - # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of # the default top-level location. set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" + ) # Generated plugin build rules, which manage building the plugins and adding # them to the application. @@ -109,19 +86,22 @@ set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) + COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) + COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) + COMPONENT Runtime) -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/linux/build/frostdart.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. @@ -130,10 +110,10 @@ install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) + COMPONENT Runtime) endif() From 6d7db533e10a313ff47f95fe8438794ee9438b90 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 2 Aug 2023 12:45:07 -0600 Subject: [PATCH 07/49] fix types for quick example --- example/lib/main.dart | 12 ++++++------ lib/frostdart.dart | 19 +++++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7c18c59..9e03984 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -14,19 +14,19 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - late CResult_MultisigConfigRes sumResult; + late CResult_MultisigConfigRes result; - String name = "REKT"; + String name = "ERROR"; @override void initState() { super.initState(); - sumResult = frostdart.newMultisigConfig( - name: "Name AAAAAA", + result = frostdart.newMultisigConfig( + name: "Some kind of name", threshold: 3, participants: ["jimmy", "john", "toby"]); - // name = frostdart.multisigName(configRes: sumResult.value.ref); + name = frostdart.multisigName(configRes: result.value); } @override @@ -51,7 +51,7 @@ class _MyAppState extends State { ), spacerSmall, Text( - 'Type of result: ${sumResult.runtimeType}', + 'Type of result: ${result.runtimeType}', style: textStyle, textAlign: TextAlign.center, ), diff --git a/lib/frostdart.dart b/lib/frostdart.dart index cebefca..5e79dcf 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -30,12 +30,16 @@ CResult_MultisigConfigRes newMultisigConfig({ }) { ffi.Pointer multisigName = name.toNativeUtf8().cast(); - final joined = participants.join(); - ffi.Pointer parts = joined.toNativeUtf8().cast(); + ffi.Pointer participantsPointer = + calloc(participants.length); - ffi.Pointer participantsPointer = calloc(); - participantsPointer.ref.ptr = parts; - participantsPointer.ref.len = joined.length; + for (int i = 0; i < participants.length; i++) { + final p = participants[i]; + final svp = calloc(); + svp.ref.ptr = p.toNativeUtf8().cast(); + svp.ref.len = p.length; + participantsPointer[i] = svp.ref; + } final result = _bindings.new_multisig_config( multisigName, @@ -46,14 +50,13 @@ CResult_MultisigConfigRes newMultisigConfig({ ); calloc.free(multisigName); - calloc.free(parts); calloc.free(participantsPointer); return result; } -String multisigName({required MultisigConfigRes configRes}) { - final result = _bindings.multisig_name(configRes.config); +String multisigName({required ffi.Pointer configRes}) { + final result = _bindings.multisig_name(configRes.ref.config); final bytes = result.ptr.asTypedList(result.len); final String name = String.fromCharCodes(bytes); From 8e2183e743f14544bf4986cd4bf92d8f1282c7f6 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 2 Aug 2023 15:20:26 -0600 Subject: [PATCH 08/49] flight param refactor and added custom exception --- example/lib/main.dart | 6 +++-- lib/frostdart.dart | 15 ++++++++--- lib/util.dart | 63 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 lib/util.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 9e03984..2c2b0a8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:ffi'; + import 'package:flutter/material.dart'; import 'package:frostdart/frostdart.dart' as frostdart; import 'package:frostdart/frostdart_bindings_generated.dart'; @@ -14,7 +16,7 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - late CResult_MultisigConfigRes result; + late Pointer result; String name = "ERROR"; @@ -26,7 +28,7 @@ class _MyAppState extends State { threshold: 3, participants: ["jimmy", "john", "toby"]); - name = frostdart.multisigName(configRes: result.value); + name = frostdart.multisigName(multisigConfigPointer: result.ref.config); } @override diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 5e79dcf..524428e 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:frostdart/frostdart_bindings_generated.dart'; +import 'package:frostdart/util.dart'; const String _libName = 'frostdart'; @@ -23,7 +24,7 @@ final ffi.DynamicLibrary _dylib = () { /// The bindings to the native functions in [_dylib]. final FrostdartBindings _bindings = FrostdartBindings(_dylib); -CResult_MultisigConfigRes newMultisigConfig({ +ffi.Pointer newMultisigConfig({ required String name, required int threshold, required List participants, @@ -52,11 +53,17 @@ CResult_MultisigConfigRes newMultisigConfig({ calloc.free(multisigName); calloc.free(participantsPointer); - return result; + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } } -String multisigName({required ffi.Pointer configRes}) { - final result = _bindings.multisig_name(configRes.ref.config); +String multisigName({ + required ffi.Pointer multisigConfigPointer, +}) { + final result = _bindings.multisig_name(multisigConfigPointer); final bytes = result.ptr.asTypedList(result.len); final String name = String.fromCharCodes(bytes); diff --git a/lib/util.dart b/lib/util.dart new file mode 100644 index 0000000..50e0f7a --- /dev/null +++ b/lib/util.dart @@ -0,0 +1,63 @@ +class FrostdartException implements Exception { + final int errorCode; + + FrostdartException({required this.errorCode}); + + @override + String toString() { + return "FrostdartException: ${getErrorName(errorCode)}"; + } +} + +const int SUCCESS = 0; + +String getErrorName(int errorCode) { + switch (errorCode) { + case 101: + return 'UNKNOWN_ERROR'; + case 102: + return 'INVALID_ENCODING_ERROR'; + case 103: + return 'INVALID_PARTICIPANT_ERROR'; + case 104: + return 'INVALID_SHARE_ERROR'; + case 201: + return 'ZERO_PARAMETER_ERROR'; + case 202: + return 'INVALID_THRESHOLD_ERROR'; + case 203: + return 'INVALID_NAME_ERROR'; + case 204: + return 'UNKNOWN_LANGUAGE_ERROR'; + case 205: + return 'INVALID_SEED_ERROR'; + case 206: + return 'INVALID_AMOUNT_OF_COMMITMENTS_ERROR'; + case 207: + return 'INVALID_COMMITMENTS_ERROR'; + case 208: + return 'INVALID_AMOUNT_OF_SHARES_ERROR'; + case 301: + return 'INVALID_OUTPUT_ERROR'; + case 302: + return 'INVALID_ADDRESS_ERROR'; + case 303: + return 'INVALID_NETWORK_ERROR'; + case 304: + return 'NO_INPUTS_ERROR'; + case 305: + return 'NO_OUTPUTS_ERROR'; + case 306: + return 'DUST_ERROR'; + case 307: + return 'NOT_ENOUGH_FUNDS_ERROR'; + case 308: + return 'TOO_LARGE_TRANSACTION_ERROR'; + case 309: + return 'WRONG_KEYS_ERROR'; + case 310: + return 'INVALID_PREPROCESS_ERROR'; + default: + return 'UNKNOWN ERROR CODE "$errorCode"'; + } +} From 374f7d645c00cd7580bbef173bdafcdc371828bc Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 2 Aug 2023 17:42:12 -0600 Subject: [PATCH 09/49] wrap all bound functions, converting non opaque types to dart native types --- lib/frostdart.dart | 523 +++++++++++++++++++++++++++++++++++++++++++-- lib/output.dart | 15 ++ lib/util.dart | 20 ++ 3 files changed, 545 insertions(+), 13 deletions(-) create mode 100644 lib/output.dart diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 524428e..ffa983b 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -1,8 +1,10 @@ import 'dart:ffi' as ffi; import 'dart:io'; +import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:frostdart/frostdart_bindings_generated.dart'; +import 'package:frostdart/output.dart'; import 'package:frostdart/util.dart'; const String _libName = 'frostdart'; @@ -24,6 +26,86 @@ final ffi.DynamicLibrary _dylib = () { /// The bindings to the native functions in [_dylib]. final FrostdartBindings _bindings = FrostdartBindings(_dylib); +// ============================================================================= +// ===== wrapped functions to make them as close to pure dart as possible ====== +//TODO: check missing frees + +void freeOwnedString(OwnedString ownedString) { + return _bindings.free_owned_string(ownedString); +} + +String multisigName({ + required ffi.Pointer multisigConfigPointer, +}) { + final result = _bindings.multisig_name(multisigConfigPointer); + + final bytes = result.ptr.asTypedList(result.len); + final String name = String.fromCharCodes(bytes); + + return name; +} + +int multisigThreshold({ + required ffi.Pointer multisigConfigPointer, +}) { + return _bindings.multisig_threshold(multisigConfigPointer); +} + +int multisigParticipants({ + required ffi.Pointer multisigConfigPointer, +}) { + return _bindings.multisig_participants(multisigConfigPointer); +} + +String multisigParticipant({ + required ffi.Pointer multisigConfigPointer, + required int index, +}) { + final stringView = _bindings.multisig_participant( + multisigConfigPointer, + index, + ); + + final utf8Pointer = stringView.ptr.cast(); + final string = utf8Pointer.toDartString(length: stringView.len); + + calloc.free(utf8Pointer); + + return string; +} + +Uint8List multisigSalt({ + required ffi.Pointer multisigConfigPointer, +}) { + final uint8Pointer = _bindings.multisig_salt(multisigConfigPointer); + final bytes = uint8Pointer.asTypedList(SALT_BYTES_LENGTH); + + calloc.free(uint8Pointer); + + return bytes; +} + +ffi.Pointer multisigConfig({ + required ffi.Pointer multisigConfigWithNamePointer, +}) { + return _bindings.multisig_config(multisigConfigWithNamePointer); +} + +String multisigMyName({ + required ffi.Pointer multisigConfigWithNamePointer, +}) { + final stringView = _bindings.multisig_my_name( + multisigConfigWithNamePointer, + ); + + final utf8Pointer = stringView.ptr.cast(); + final string = utf8Pointer.toDartString(length: stringView.len); + + calloc.free(utf8Pointer); + + return string; +} + ffi.Pointer newMultisigConfig({ required String name, required int threshold, @@ -31,15 +113,22 @@ ffi.Pointer newMultisigConfig({ }) { ffi.Pointer multisigName = name.toNativeUtf8().cast(); - ffi.Pointer participantsPointer = - calloc(participants.length); + ffi.Pointer participantsPointer = calloc( + participants.length, + ); for (int i = 0; i < participants.length; i++) { - final p = participants[i]; - final svp = calloc(); - svp.ref.ptr = p.toNativeUtf8().cast(); - svp.ref.len = p.length; - participantsPointer[i] = svp.ref; + // TODO: is this needed? + // final participant = participants[i]; + // final stringViewPointer = calloc(); + // stringViewPointer.ref.ptr = participant.toNativeUtf8().cast(); + // stringViewPointer.ref.len = participant.length; + // participantsPointer[i] = stringViewPointer.ref; + + // TODO: or does this suffice? + participantsPointer[i].len = participants[i].length; + participantsPointer[i].ptr = + participants[i].toNativeUtf8().cast(); } final result = _bindings.new_multisig_config( @@ -60,13 +149,421 @@ ffi.Pointer newMultisigConfig({ } } -String multisigName({ - required ffi.Pointer multisigConfigPointer, +ffi.Pointer decodeMultisigConfig({ + required String multisigConfig, }) { - final result = _bindings.multisig_name(multisigConfigPointer); + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = multisigConfig.toNativeUtf8().cast(); + stringViewPointer.ref.len = multisigConfig.length; - final bytes = result.ptr.asTypedList(result.len); - final String name = String.fromCharCodes(bytes); + final result = _bindings.decode_multisig_config(stringViewPointer.ref); - return name; + calloc.free(stringViewPointer.ref.ptr); + calloc.free(stringViewPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer startKeyGen({ + required ffi.Pointer multisigConfig, + required String myName, + required Language language, +}) { + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = myName.toNativeUtf8().cast(); + stringViewPointer.ref.len = myName.length; + + final result = _bindings.start_key_gen( + multisigConfig, + stringViewPointer.ref, + language.code, + ); + + calloc.free(stringViewPointer.ref.ptr); + calloc.free(stringViewPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer getSecretShares({ + required ffi.Pointer multisigConfigWithName, + required String seed, + required Language language, + required ffi.Pointer machine, + required List commitments, +}) { + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = seed.toNativeUtf8().cast(); + stringViewPointer.ref.len = seed.length; + + ffi.Pointer commitmentsPointer = + calloc(commitments.length); + + for (int i = 0; i < commitments.length; i++) { + final commitment = commitments[i]; + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = commitment.toNativeUtf8().cast(); + stringViewPointer.ref.len = commitment.length; + commitmentsPointer[i] = stringViewPointer.ref; + } + + final result = _bindings.get_secret_shares( + multisigConfigWithName, + language.code, + stringViewPointer.ref, + machine, + commitmentsPointer, + commitments.length, + ); + + calloc.free(stringViewPointer.ref.ptr); + calloc.free(stringViewPointer); + calloc.free(commitmentsPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer completeKeyGen({ + required ffi.Pointer multisigConfigWithName, + required ffi.Pointer machineAndCommitments, + required List shares, +}) { + ffi.Pointer sharesPointer = calloc(shares.length); + + for (int i = 0; i < shares.length; i++) { + final share = shares[i]; + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = share.toNativeUtf8().cast(); + stringViewPointer.ref.len = share.length; + sharesPointer[i] = stringViewPointer.ref; + } + + final result = _bindings.complete_key_gen( + multisigConfigWithName, + machineAndCommitments.ref, + sharesPointer, + shares.length, + ); + + calloc.free(sharesPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +String serializeKeys({ + required ffi.Pointer keys, +}) { + final ownedString = _bindings.serialize_keys(keys); + + final string = ownedString.ptr.cast().toDartString( + length: ownedString.len, + ); + + _bindings.free_owned_string(ownedString); + + return string; +} + +ffi.Pointer deserializeKeys({ + required String keys, +}) { + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = keys.toNativeUtf8().cast(); + stringViewPointer.ref.len = keys.length; + + final result = _bindings.deserialize_keys(stringViewPointer.ref); + + calloc.free(stringViewPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +Output convertOutput({ + required ffi.Pointer ownedPortableOutputPointer, +}) { + final hashPointer = _bindings.output_hash(ownedPortableOutputPointer); + final hash = hashPointer.asTypedList(HASH_BYTES_LENGTH); + calloc.free(hashPointer); + + final vout = _bindings.output_vout(ownedPortableOutputPointer); + + final value = _bindings.output_value(ownedPortableOutputPointer); + + final scriptPubKeyLength = + _bindings.output_script_pubkey_len(ownedPortableOutputPointer); + + final scriptPubKeyPointer = _bindings.output_hash(ownedPortableOutputPointer); + final scriptPubKey = scriptPubKeyPointer.asTypedList(scriptPubKeyLength); + calloc.free(scriptPubKeyPointer); + + return Output( + hash: hash, + vout: vout, + value: value, + scriptPubKey: scriptPubKey, + ); +} + +int signInputs({ + required ffi.Pointer signConfigPointer, +}) { + return _bindings.sign_inputs(signConfigPointer); +} + +ffi.Pointer> signInput({ + required ffi.Pointer signConfigPointer, + required int index, +}) { + return _bindings.sign_input(signConfigPointer, index); +} + +int signPayments({ + required ffi.Pointer signConfigPointer, +}) { + return _bindings.sign_payments(signConfigPointer); +} + +String signPaymentAddress({ + required ffi.Pointer signConfigPointer, + required int index, +}) { + final stringView = _bindings.sign_payment_address( + signConfigPointer, + index, + ); + + final utf8Pointer = stringView.ptr.cast(); + final string = utf8Pointer.toDartString(length: stringView.len); + + calloc.free(utf8Pointer); + + return string; +} + +int signPaymentAmount({ + required ffi.Pointer signConfigPointer, + required int index, +}) { + return _bindings.sign_payment_amount(signConfigPointer, index); +} + +String signChange({ + required ffi.Pointer signConfigPointer, +}) { + final stringView = _bindings.sign_change( + signConfigPointer, + ); + + final utf8Pointer = stringView.ptr.cast(); + final string = utf8Pointer.toDartString(length: stringView.len); + + calloc.free(utf8Pointer); + + return string; +} + +int signFeePerWeight({ + required ffi.Pointer signConfigPointer, + required int index, +}) { + return _bindings.sign_fee_per_weight(signConfigPointer); +} + +ffi.Pointer newSignConfig({ + required int network, + required List outputs, + required int payments, + required List paymentAddresses, + required List paymentAmounts, + required String change, + required int feePerWeight, +}) { + final outputsPointer = calloc(outputs.length); + for (int i = 0; i < outputs.length; i++) { + outputsPointer[i].vout = outputs[i].vout; + outputsPointer[i].value = outputs[i].value; + + final hashLength = outputs[i].hash.length; + final hashArr = ffi.Array(hashLength); + for (int j = 0; j < hashLength; j++) { + hashArr[j] = outputs[i].hash[j]; + } + outputsPointer[i].hash = hashArr; + outputsPointer[i].script_pubkey_len = outputs[i].scriptPubKey.length; + + outputsPointer[i].script_pubkey = + calloc(outputsPointer[i].script_pubkey_len); + for (int j = 0; j < outputsPointer[i].script_pubkey_len; j++) { + outputsPointer[i].script_pubkey.elementAt(j).value = outputs[i].hash[j]; + } + } + + final paymentAddressesPointer = calloc( + paymentAddresses.length, + ); + for (int i = 0; i < paymentAddresses.length; i++) { + paymentAddressesPointer[i].len = paymentAddresses[i].length; + paymentAddressesPointer[i].ptr = + paymentAddresses[i].toNativeUtf8().cast(); + } + + final paymentAmountsPointer = calloc(paymentAmounts.length); + for (int i = 0; i < paymentAmounts.length; i++) { + paymentAmountsPointer[i] = paymentAmounts[i]; + } + + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = change + .toNativeUtf8( + allocator: calloc, + ) + .cast(); + stringViewPointer.ref.len = change.length; + + final result = _bindings.new_sign_config( + network, + outputsPointer, + outputs.length, + payments, + paymentAddressesPointer, + paymentAmountsPointer, + stringViewPointer.ref, + feePerWeight, + ); + + // TODO: frees + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer decodeSignConfig({ + required int network, + required String encodedSignConfig, +}) { + final stringViewPointer = calloc(); + stringViewPointer.ref.ptr = encodedSignConfig + .toNativeUtf8( + allocator: calloc, + ) + .cast(); + stringViewPointer.ref.len = encodedSignConfig.length; + + final result = _bindings.decode_sign_config( + network, + stringViewPointer.ref, + ); + + calloc.free(stringViewPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer attemptSign({ + required ffi.Pointer thresholdKeysWrapperPointer, + required ffi.Pointer> signConfigPointer, +}) { + final result = _bindings.attempt_sign( + thresholdKeysWrapperPointer, + signConfigPointer, + ); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +ffi.Pointer continueSign({ + required ffi.Pointer machine, + required List preprocesses, +}) { + final preprocessesPointer = calloc(preprocesses.length); + for (int i = 0; i < preprocesses.length; i++) { + preprocessesPointer[i].len = preprocesses[i].length; + preprocessesPointer[i].ptr = preprocesses[i] + .toNativeUtf8( + allocator: calloc, + ) + .cast(); + } + + final result = _bindings.continue_sign( + machine, + preprocessesPointer, + preprocesses.length, + ); + + calloc.free(preprocessesPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + return result.value; + } +} + +String completeSign({ + required ffi.Pointer machine, + required List shares, +}) { + final sharesPointer = calloc(shares.length); + for (int i = 0; i < shares.length; i++) { + sharesPointer[i].len = shares[i].length; + sharesPointer[i].ptr = shares[i] + .toNativeUtf8( + allocator: calloc, + ) + .cast(); + } + + final result = _bindings.complete_sign( + machine, + sharesPointer, + shares.length, + ); + + calloc.free(sharesPointer); + + if (result.err != SUCCESS) { + throw FrostdartException(errorCode: result.err); + } else { + final ownedString = result.value.ref; + + final string = ownedString.ptr.cast().toDartString( + length: ownedString.len, + ); + + _bindings.free_owned_string(ownedString); + + return string; + } } diff --git a/lib/output.dart b/lib/output.dart new file mode 100644 index 0000000..fc1cb51 --- /dev/null +++ b/lib/output.dart @@ -0,0 +1,15 @@ +import 'dart:typed_data'; + +class Output { + final Uint8List hash; + final int vout; + final int value; + final Uint8List scriptPubKey; + + Output({ + required this.hash, + required this.vout, + required this.value, + required this.scriptPubKey, + }); +} diff --git a/lib/util.dart b/lib/util.dart index 50e0f7a..c6eef1b 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -1,3 +1,5 @@ +import 'package:frostdart/frostdart_bindings_generated.dart'; + class FrostdartException implements Exception { final int errorCode; @@ -9,8 +11,26 @@ class FrostdartException implements Exception { } } +const int SALT_BYTES_LENGTH = 32; +const int HASH_BYTES_LENGTH = 32; const int SUCCESS = 0; +enum Language { + english(LANGUAGE_ENGLISH), + chineseSimplified(LANGUAGE_CHINESE_SIMPLIFIED), + chineseTraditional(LANGUAGE_CHINESE_TRADITIONAL), + french(LANGUAGE_FRENCH), + italian(LANGUAGE_ITALIAN), + japanese(LANGUAGE_JAPANESE), + korean(LANGUAGE_KOREAN), + spanish(LANGUAGE_SPANISH), + ; + + final int code; + + const Language(this.code); +} + String getErrorName(int errorCode) { switch (errorCode) { case 101: From d41e35449ef1c1c858f653e3fcb94f7b75f023ce Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 09:59:07 -0600 Subject: [PATCH 10/49] example run ui --- example/lib/frost_sample_run.dart | 15 ++++ example/lib/main.dart | 109 ++++++++++++++++++------------ 2 files changed, 81 insertions(+), 43 deletions(-) create mode 100644 example/lib/frost_sample_run.dart diff --git a/example/lib/frost_sample_run.dart b/example/lib/frost_sample_run.dart new file mode 100644 index 0000000..652880b --- /dev/null +++ b/example/lib/frost_sample_run.dart @@ -0,0 +1,15 @@ +import 'package:flutter/foundation.dart'; + +abstract class FrostSampleRunner { + static String _run(int dummy) { + // do things + + // return "success" or return early with error message string + return "success"; + } + + static Future run() async { + await Future.delayed(const Duration(seconds: 2)); + return await compute(_run, 1); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 2c2b0a8..97a0cbc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,5 @@ -import 'dart:ffi'; - import 'package:flutter/material.dart'; -import 'package:frostdart/frostdart.dart' as frostdart; -import 'package:frostdart/frostdart_bindings_generated.dart'; +import 'package:frostdart_example/frost_sample_run.dart'; void main() { runApp(const MyApp()); @@ -16,57 +13,83 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - late Pointer result; + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('frostdart'), + ), + body: const Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Content(), + ), + ], + ), + ), + ); + } +} - String name = "ERROR"; +class Content extends StatefulWidget { + const Content({super.key}); + + @override + State createState() => _ContentState(); +} + +class _ContentState extends State { + String? result; + + late bool enableButton; @override void initState() { + enableButton = true; super.initState(); - result = frostdart.newMultisigConfig( - name: "Some kind of name", - threshold: 3, - participants: ["jimmy", "john", "toby"]); - - name = frostdart.multisigName(multisigConfigPointer: result.ref.config); } @override Widget build(BuildContext context) { const textStyle = TextStyle(fontSize: 25); const spacerSmall = SizedBox(height: 10); - return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Native Packages'), - ), - body: SingleChildScrollView( - child: Container( - padding: const EdgeInsets.all(10), - child: Column( - children: [ - const Text( - 'This calls a native function through FFI that is shipped as source in the package. ' - 'The native code is built as part of the Flutter Runner build.', - style: textStyle, - textAlign: TextAlign.center, - ), - spacerSmall, - Text( - 'Type of result: ${result.runtimeType}', - style: textStyle, - textAlign: TextAlign.center, - ), - spacerSmall, - Text( - 'name: $name', - style: textStyle, - textAlign: TextAlign.center, - ), - ], - ), + return Container( + padding: const EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () async { + setState(() { + enableButton = false; + }); + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => + const AlertDialog(title: Text("Running"))); + result = await FrostSampleRunner.run(); + if (mounted) { + Navigator.of(context).pop(); + setState(() { + enableButton = true; + }); + } + }, + child: const Text("RUN"), ), - ), + spacerSmall, + spacerSmall, + spacerSmall, + Text( + 'Result: ${result.toString()}', + style: textStyle, + textAlign: TextAlign.center, + ), + ], ), ); } From 4f05a15b27e73d35ff431f5cd5e8fde9b2922396 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 10:01:14 -0600 Subject: [PATCH 11/49] OwnedString toDartString extension --- lib/frostdart.dart | 8 ++------ lib/util.dart | 10 ++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index ffa983b..02fa6fd 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -271,9 +271,7 @@ String serializeKeys({ }) { final ownedString = _bindings.serialize_keys(keys); - final string = ownedString.ptr.cast().toDartString( - length: ownedString.len, - ); + final string = ownedString.toDartString(); _bindings.free_owned_string(ownedString); @@ -558,9 +556,7 @@ String completeSign({ } else { final ownedString = result.value.ref; - final string = ownedString.ptr.cast().toDartString( - length: ownedString.len, - ); + final string = ownedString.toDartString(); _bindings.free_owned_string(ownedString); diff --git a/lib/util.dart b/lib/util.dart index c6eef1b..cdcf359 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -1,3 +1,4 @@ +import 'package:ffi/ffi.dart'; import 'package:frostdart/frostdart_bindings_generated.dart'; class FrostdartException implements Exception { @@ -81,3 +82,12 @@ String getErrorName(int errorCode) { return 'UNKNOWN ERROR CODE "$errorCode"'; } } + +extension OwnedStringExt on OwnedString { + String toDartString() { + final string = ptr.cast().toDartString( + length: len, + ); + return string; + } +} From f23682106535c16ddfbeb5f867663428c4ce8802 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 11:06:52 -0600 Subject: [PATCH 12/49] WIP sample testing run --- example/lib/frost_sample_run.dart | 81 ++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/example/lib/frost_sample_run.dart b/example/lib/frost_sample_run.dart index 652880b..a059abb 100644 --- a/example/lib/frost_sample_run.dart +++ b/example/lib/frost_sample_run.dart @@ -1,15 +1,84 @@ +import 'dart:ffi'; + import 'package:flutter/foundation.dart'; +import 'package:frostdart/frostdart.dart'; +import 'package:frostdart/util.dart'; abstract class FrostSampleRunner { - static String _run(int dummy) { - // do things + static String _run(int? dummy) { + try { + // do things + + final config = newMultisigConfig( + name: "alice", + threshold: 1, + participants: [ + "alice", + "bob", + ], + ); + + final encodedConfig = config.ref.encoded.toDartString(); + + final startGenAlice = startKeyGen( + multisigConfig: decodeMultisigConfig(multisigConfig: encodedConfig), + myName: "alice", + language: Language.english, + ); + + final startGenBob = startKeyGen( + multisigConfig: decodeMultisigConfig(multisigConfig: encodedConfig), + myName: "bob", + language: Language.english, + ); + + final seedAlice = startGenAlice.ref.seed.toDartString(); + final seedBob = startGenBob.ref.seed.toDartString(); + debugPrint("seedAlice: $seedAlice"); + debugPrint("seedBob: $seedBob"); + + final commitments = [ + startGenAlice.ref.commitments.toDartString(), + startGenBob.ref.commitments.toDartString(), + ]; + debugPrint("commitments: $commitments"); + + final secretSharesAlice = getSecretShares( + multisigConfigWithName: startGenAlice.ref.config, + seed: seedAlice, + language: Language.english, + machine: startGenAlice.ref.machine, + commitments: commitments, + ); + final secretSharesBob = getSecretShares( + multisigConfigWithName: startGenBob.ref.config, + seed: seedBob, + language: Language.english, + machine: startGenBob.ref.machine, + commitments: commitments, + ); + + final List shares = [ + secretSharesAlice.ref.shares.toDartString(), + secretSharesBob.ref.shares.toDartString(), + ]; + debugPrint("shares: $shares"); + + final completeGen = completeKeyGen( + multisigConfigWithName: startGenAlice.ref.config, + machineAndCommitments: secretSharesAlice, + shares: shares, + ); - // return "success" or return early with error message string - return "success"; + // return "success" or return early with error message string + return "success"; + } catch (e, s) { + debugPrint("run error: $e\n$s"); + return e.toString(); + } } static Future run() async { - await Future.delayed(const Duration(seconds: 2)); - return await compute(_run, 1); + return await compute(_run, null); } } From 2e801aa3f31de2b43cdaa988f739ba2c1231d3f8 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 11:57:06 -0600 Subject: [PATCH 13/49] update ref --- src/serai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serai b/src/serai index 1674b21..a9a9260 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit 1674b21712a87297bf30c291163a21e6158212f7 +Subproject commit a9a9260eabdbc7eb20ddf54f8e413e64e747f024 From 9e78f56a33e9448189d4e345cc01e492b5734fc1 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 11:57:41 -0600 Subject: [PATCH 14/49] full rebuild in build script --- scripts/linux/build_all.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 14d31c0..b86eeb5 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -4,6 +4,8 @@ ROOT_DIR="$(pwd)/../.." mkdir -p build +rm -rf "$ROOT_DIR"/src/serai/target + cd "$ROOT_DIR"/src/serai/hrf || exit if [ "$IS_ARM" = true ] ; then echo "Building arm frostdart" From ad2a070ab1469e74ecdfa849fb366f295dd1996e Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Aug 2023 13:53:20 -0600 Subject: [PATCH 15/49] update ref --- src/serai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serai b/src/serai index a9a9260..001d60c 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit a9a9260eabdbc7eb20ddf54f8e413e64e747f024 +Subproject commit 001d60cb46169061d87ec2115fa96cb1d45a5043 From 9e18598b261f4e028b80e7c2e48ea7e580270cfd Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 07:55:24 -0600 Subject: [PATCH 16/49] update ref and affected bindings --- lib/frostdart.dart | 2 +- lib/frostdart_bindings_generated.dart | 8 ++++---- src/serai | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 02fa6fd..ed4257c 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -486,7 +486,7 @@ ffi.Pointer decodeSignConfig({ ffi.Pointer attemptSign({ required ffi.Pointer thresholdKeysWrapperPointer, - required ffi.Pointer> signConfigPointer, + required ffi.Pointer signConfigPointer, }) { final result = _bindings.attempt_sign( thresholdKeysWrapperPointer, diff --git a/lib/frostdart_bindings_generated.dart b/lib/frostdart_bindings_generated.dart index e8e5d4b..1333e40 100644 --- a/lib/frostdart_bindings_generated.dart +++ b/lib/frostdart_bindings_generated.dart @@ -539,7 +539,7 @@ class FrostdartBindings { CResult_AttemptSignRes attempt_sign( ffi.Pointer keys, - ffi.Pointer> config, + ffi.Pointer config, ) { return _attempt_sign( keys, @@ -550,10 +550,10 @@ class FrostdartBindings { late final _attempt_signPtr = _lookup< ffi.NativeFunction< CResult_AttemptSignRes Function(ffi.Pointer, - ffi.Pointer>)>>('attempt_sign'); + ffi.Pointer)>>('attempt_sign'); late final _attempt_sign = _attempt_signPtr.asFunction< - CResult_AttemptSignRes Function(ffi.Pointer, - ffi.Pointer>)>(); + CResult_AttemptSignRes Function( + ffi.Pointer, ffi.Pointer)>(); CResult_ContinueSignRes continue_sign( ffi.Pointer machine, diff --git a/src/serai b/src/serai index 001d60c..0298704 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit 001d60cb46169061d87ec2115fa96cb1d45a5043 +Subproject commit 02987043d2c097ffcc3bea8c1dce67086707d1bc From 2fd5ec3f265f1e7cda7881cf25b3e244b264264e Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 08:17:34 -0600 Subject: [PATCH 17/49] basic working keygen example --- example/lib/frost_sample_run.dart | 54 +++++++++++++++++++++++++------ example/lib/main.dart | 25 ++++++++------ lib/util.dart | 1 + 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/example/lib/frost_sample_run.dart b/example/lib/frost_sample_run.dart index a059abb..f346384 100644 --- a/example/lib/frost_sample_run.dart +++ b/example/lib/frost_sample_run.dart @@ -5,11 +5,13 @@ import 'package:frostdart/frostdart.dart'; import 'package:frostdart/util.dart'; abstract class FrostSampleRunner { - static String _run(int? dummy) { - try { - // do things + static Future runKeygen() async { + return await compute(_runKeygen, null); + } - final config = newMultisigConfig( + static String _runKeygen(int? dummy) { + try { + final sharedMultisigConfig = newMultisigConfig( name: "alice", threshold: 1, participants: [ @@ -18,7 +20,7 @@ abstract class FrostSampleRunner { ], ); - final encodedConfig = config.ref.encoded.toDartString(); + final encodedConfig = sharedMultisigConfig.ref.encoded.toDartString(); final startGenAlice = startKeyGen( multisigConfig: decodeMultisigConfig(multisigConfig: encodedConfig), @@ -64,12 +66,48 @@ abstract class FrostSampleRunner { ]; debugPrint("shares: $shares"); - final completeGen = completeKeyGen( + final completeGenAlice = completeKeyGen( multisigConfigWithName: startGenAlice.ref.config, machineAndCommitments: secretSharesAlice, shares: shares, ); + final completeGenBob = completeKeyGen( + multisigConfigWithName: startGenBob.ref.config, + machineAndCommitments: secretSharesBob, + shares: shares, + ); + + final idAlice = Uint8List.fromList( + List.generate( + MULTISIG_ID_LENGTH, + (index) => completeGenAlice.ref.multisig_id[index], + ), + ); + final idBob = Uint8List.fromList( + List.generate( + MULTISIG_ID_LENGTH, + (index) => completeGenBob.ref.multisig_id[index], + ), + ); + debugPrint("ID Alice: $idAlice"); + debugPrint("ID Bob: $idBob"); + + final recoveryAlice = completeGenAlice.ref.recovery.toDartString(); + final recoveryBob = completeGenBob.ref.recovery.toDartString(); + debugPrint("recoveryAlice: $recoveryAlice"); + debugPrint("recoveryBob: $recoveryBob"); + + for (int i = 0; i < MULTISIG_ID_LENGTH; i++) { + if (idAlice[i] != idBob[i]) { + return "IDs don't match!"; + } + } + + if (recoveryAlice != recoveryBob) { + return "Recovery strings don't match!"; + } + // return "success" or return early with error message string return "success"; } catch (e, s) { @@ -77,8 +115,4 @@ abstract class FrostSampleRunner { return e.toString(); } } - - static Future run() async { - return await compute(_run, null); - } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 97a0cbc..61682dc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -54,7 +54,7 @@ class _ContentState extends State { @override Widget build(BuildContext context) { const textStyle = TextStyle(fontSize: 25); - const spacerSmall = SizedBox(height: 10); + const spacerSmall = SizedBox(height: 30); return Container( padding: const EdgeInsets.all(10), child: Column( @@ -67,11 +67,15 @@ class _ContentState extends State { enableButton = false; }); showDialog( - barrierDismissible: false, - context: context, - builder: (context) => - const AlertDialog(title: Text("Running"))); - result = await FrostSampleRunner.run(); + barrierDismissible: false, + context: context, + builder: (context) => const AlertDialog( + title: Text( + "Running", + ), + ), + ); + result = await FrostSampleRunner.runKeygen(); if (mounted) { Navigator.of(context).pop(); setState(() { @@ -79,13 +83,14 @@ class _ContentState extends State { }); } }, - child: const Text("RUN"), + child: const Text( + "RUN SIMPLE KEYGEN TEST", + style: textStyle, + ), ), spacerSmall, - spacerSmall, - spacerSmall, Text( - 'Result: ${result.toString()}', + 'Keygen result: ${result.toString()}', style: textStyle, textAlign: TextAlign.center, ), diff --git a/lib/util.dart b/lib/util.dart index cdcf359..5fe4fb4 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -14,6 +14,7 @@ class FrostdartException implements Exception { const int SALT_BYTES_LENGTH = 32; const int HASH_BYTES_LENGTH = 32; +const int MULTISIG_ID_LENGTH = 32; const int SUCCESS = 0; enum Language { From 47de72103ce10561352d9df871094054751218aa Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 09:19:35 -0600 Subject: [PATCH 18/49] remove unnecessary param and check lengths match --- lib/frostdart.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index ed4257c..57fbc5a 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -390,12 +390,15 @@ int signFeePerWeight({ ffi.Pointer newSignConfig({ required int network, required List outputs, - required int payments, required List paymentAddresses, required List paymentAmounts, required String change, required int feePerWeight, }) { + if (paymentAddresses.length != paymentAmounts.length) { + throw Exception("paymentAddresses.length != paymentAmounts.length"); + } + final outputsPointer = calloc(outputs.length); for (int i = 0; i < outputs.length; i++) { outputsPointer[i].vout = outputs[i].vout; @@ -442,7 +445,7 @@ ffi.Pointer newSignConfig({ network, outputsPointer, outputs.length, - payments, + paymentAddresses.length, paymentAddressesPointer, paymentAmountsPointer, stringViewPointer.ref, From cbdcd11408589fed983043ba04fc94bf144ffdc1 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 09:35:49 -0600 Subject: [PATCH 19/49] array access fix --- lib/frostdart.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 57fbc5a..6c4c9cd 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -405,17 +405,16 @@ ffi.Pointer newSignConfig({ outputsPointer[i].value = outputs[i].value; final hashLength = outputs[i].hash.length; - final hashArr = ffi.Array(hashLength); for (int j = 0; j < hashLength; j++) { - hashArr[j] = outputs[i].hash[j]; + outputsPointer[i].hash[j] = outputs[i].hash[j]; } - outputsPointer[i].hash = hashArr; outputsPointer[i].script_pubkey_len = outputs[i].scriptPubKey.length; outputsPointer[i].script_pubkey = calloc(outputsPointer[i].script_pubkey_len); for (int j = 0; j < outputsPointer[i].script_pubkey_len; j++) { - outputsPointer[i].script_pubkey.elementAt(j).value = outputs[i].hash[j]; + outputsPointer[i].script_pubkey.elementAt(j).value = + outputs[i].scriptPubKey[j]; } } From 5e2d0ec29c06a2e46a9d3cc97a3f070567b3f0c5 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 10:38:46 -0600 Subject: [PATCH 20/49] updated serai ref and bindings --- lib/frostdart_bindings_generated.dart | 32 +++++++++++++++++++++++++++ src/serai | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/frostdart_bindings_generated.dart b/lib/frostdart_bindings_generated.dart index 1333e40..7dc60d4 100644 --- a/lib/frostdart_bindings_generated.dart +++ b/lib/frostdart_bindings_generated.dart @@ -300,6 +300,38 @@ class FrostdartBindings { late final _deserialize_keys = _deserialize_keysPtr .asFunction(); + OwnedString address_for_keys( + int network, + ffi.Pointer keys, + ) { + return _address_for_keys( + network, + keys, + ); + } + + late final _address_for_keysPtr = _lookup< + ffi.NativeFunction< + OwnedString Function(ffi.Int32, + ffi.Pointer)>>('address_for_keys'); + late final _address_for_keys = _address_for_keysPtr.asFunction< + OwnedString Function(int, ffi.Pointer)>(); + + OwnedString script_pub_key_for_keys( + ffi.Pointer keys, + ) { + return _script_pub_key_for_keys( + keys, + ); + } + + late final _script_pub_key_for_keysPtr = _lookup< + ffi.NativeFunction< + OwnedString Function( + ffi.Pointer)>>('script_pub_key_for_keys'); + late final _script_pub_key_for_keys = _script_pub_key_for_keysPtr + .asFunction)>(); + ffi.Pointer output_hash( ffi.Pointer self, ) { diff --git a/src/serai b/src/serai index 0298704..ff471d7 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit 02987043d2c097ffcc3bea8c1dce67086707d1bc +Subproject commit ff471d740f7d307dd839322ef2fac6c72960f446 From 8516dddcd4ec93715767afda2de99ac47ca3eb1f Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 16:02:59 -0600 Subject: [PATCH 21/49] Correct header --- lib/frostdart_bindings_generated.dart | 44 ++++++++++----------- lib/util.dart | 55 ++++++++++++++++----------- src/serai | 2 +- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/lib/frostdart_bindings_generated.dart b/lib/frostdart_bindings_generated.dart index 7dc60d4..18f66ad 100644 --- a/lib/frostdart_bindings_generated.dart +++ b/lib/frostdart_bindings_generated.dart @@ -844,46 +844,46 @@ const int LANGUAGE_KOREAN = 7; const int LANGUAGE_SPANISH = 8; -const int UNKNOWN_ERROR = 101; +const int UNKNOWN_ERROR = 21; -const int INVALID_ENCODING_ERROR = 102; +const int INVALID_ENCODING_ERROR = 22; -const int INVALID_PARTICIPANT_ERROR = 103; +const int INVALID_PARTICIPANT_ERROR = 23; -const int INVALID_SHARE_ERROR = 104; +const int INVALID_SHARE_ERROR = 24; -const int ZERO_PARAMETER_ERROR = 201; +const int ZERO_PARAMETER_ERROR = 41; -const int INVALID_THRESHOLD_ERROR = 202; +const int INVALID_THRESHOLD_ERROR = 42; -const int INVALID_NAME_ERROR = 203; +const int INVALID_NAME_ERROR = 43; -const int UNKNOWN_LANGUAGE_ERROR = 204; +const int UNKNOWN_LANGUAGE_ERROR = 44; -const int INVALID_SEED_ERROR = 205; +const int INVALID_SEED_ERROR = 45; -const int INVALID_AMOUNT_OF_COMMITMENTS_ERROR = 206; +const int INVALID_AMOUNT_OF_COMMITMENTS_ERROR = 46; -const int INVALID_COMMITMENTS_ERROR = 207; +const int INVALID_COMMITMENTS_ERROR = 47; -const int INVALID_AMOUNT_OF_SHARES_ERROR = 208; +const int INVALID_AMOUNT_OF_SHARES_ERROR = 48; -const int INVALID_OUTPUT_ERROR = 301; +const int INVALID_OUTPUT_ERROR = 61; -const int INVALID_ADDRESS_ERROR = 302; +const int INVALID_ADDRESS_ERROR = 62; -const int INVALID_NETWORK_ERROR = 303; +const int INVALID_NETWORK_ERROR = 63; -const int NO_INPUTS_ERROR = 304; +const int NO_INPUTS_ERROR = 64; -const int NO_OUTPUTS_ERROR = 305; +const int NO_OUTPUTS_ERROR = 65; -const int DUST_ERROR = 306; +const int DUST_ERROR = 66; -const int NOT_ENOUGH_FUNDS_ERROR = 307; +const int NOT_ENOUGH_FUNDS_ERROR = 67; -const int TOO_LARGE_TRANSACTION_ERROR = 308; +const int TOO_LARGE_TRANSACTION_ERROR = 68; -const int WRONG_KEYS_ERROR = 309; +const int WRONG_KEYS_ERROR = 69; -const int INVALID_PREPROCESS_ERROR = 310; +const int INVALID_PREPROCESS_ERROR = 70; diff --git a/lib/util.dart b/lib/util.dart index 5fe4fb4..695aef6 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -35,49 +35,49 @@ enum Language { String getErrorName(int errorCode) { switch (errorCode) { - case 101: + case UNKNOWN_ERROR: return 'UNKNOWN_ERROR'; - case 102: + case INVALID_ENCODING_ERROR: return 'INVALID_ENCODING_ERROR'; - case 103: + case INVALID_PARTICIPANT_ERROR: return 'INVALID_PARTICIPANT_ERROR'; - case 104: + case INVALID_SHARE_ERROR: return 'INVALID_SHARE_ERROR'; - case 201: + case ZERO_PARAMETER_ERROR: return 'ZERO_PARAMETER_ERROR'; - case 202: + case INVALID_THRESHOLD_ERROR: return 'INVALID_THRESHOLD_ERROR'; - case 203: + case INVALID_NAME_ERROR: return 'INVALID_NAME_ERROR'; - case 204: + case UNKNOWN_LANGUAGE_ERROR: return 'UNKNOWN_LANGUAGE_ERROR'; - case 205: + case INVALID_SEED_ERROR: return 'INVALID_SEED_ERROR'; - case 206: + case INVALID_AMOUNT_OF_COMMITMENTS_ERROR: return 'INVALID_AMOUNT_OF_COMMITMENTS_ERROR'; - case 207: + case INVALID_COMMITMENTS_ERROR: return 'INVALID_COMMITMENTS_ERROR'; - case 208: + case INVALID_AMOUNT_OF_SHARES_ERROR: return 'INVALID_AMOUNT_OF_SHARES_ERROR'; - case 301: + case INVALID_OUTPUT_ERROR: return 'INVALID_OUTPUT_ERROR'; - case 302: + case INVALID_ADDRESS_ERROR: return 'INVALID_ADDRESS_ERROR'; - case 303: + case INVALID_NETWORK_ERROR: return 'INVALID_NETWORK_ERROR'; - case 304: + case NO_INPUTS_ERROR: return 'NO_INPUTS_ERROR'; - case 305: + case NO_OUTPUTS_ERROR: return 'NO_OUTPUTS_ERROR'; - case 306: + case DUST_ERROR: return 'DUST_ERROR'; - case 307: + case NOT_ENOUGH_FUNDS_ERROR: return 'NOT_ENOUGH_FUNDS_ERROR'; - case 308: + case TOO_LARGE_TRANSACTION_ERROR: return 'TOO_LARGE_TRANSACTION_ERROR'; - case 309: + case WRONG_KEYS_ERROR: return 'WRONG_KEYS_ERROR'; - case 310: + case INVALID_PREPROCESS_ERROR: return 'INVALID_PREPROCESS_ERROR'; default: return 'UNKNOWN ERROR CODE "$errorCode"'; @@ -92,3 +92,14 @@ extension OwnedStringExt on OwnedString { return string; } } + +List hexStringToList(String hexString) { + final length = hexString.length; + List result = []; + for (int i = 0; i < length; i += 2) { + String hexByte = hexString.substring(i, i + 2); + int byteValue = int.parse(hexByte, radix: 16); + result.add(byteValue); + } + return result; +} diff --git a/src/serai b/src/serai index ff471d7..ac28bbc 160000 --- a/src/serai +++ b/src/serai @@ -1 +1 @@ -Subproject commit ff471d740f7d307dd839322ef2fac6c72960f446 +Subproject commit ac28bbc0b4df24715ad3cac4cfc8fe2e35137686 From c149bb2593e81e37175064c13f6ecb566ba9c36b Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 16:15:28 -0600 Subject: [PATCH 22/49] added new wrappers for new bindings --- lib/frostdart.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 6c4c9cd..9146ccf 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -358,6 +358,25 @@ String signPaymentAddress({ return string; } +String addressForKeys({ + required int network, + required ffi.Pointer keys, +}) { + final ownedString = _bindings.address_for_keys(network, keys); + + return ownedString.toDartString(); +} + +Uint8List scriptPubKeyForKeys({ + required ffi.Pointer keys, +}) { + final ownedString = _bindings.script_pub_key_for_keys(keys); + + final bytes = ownedString.ptr.asTypedList(ownedString.len); + + return bytes; +} + int signPaymentAmount({ required ffi.Pointer signConfigPointer, required int index, From 247db1323335b147520535d0576230b41b41b165 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 16:17:52 -0600 Subject: [PATCH 23/49] WIP signing example --- example/lib/frost_sample_run.dart | 144 +++++++++++++++++++++++++++++- example/lib/main.dart | 89 +++++++++++++----- 2 files changed, 205 insertions(+), 28 deletions(-) diff --git a/example/lib/frost_sample_run.dart b/example/lib/frost_sample_run.dart index f346384..f59ee86 100644 --- a/example/lib/frost_sample_run.dart +++ b/example/lib/frost_sample_run.dart @@ -2,22 +2,149 @@ import 'dart:ffi'; import 'package:flutter/foundation.dart'; import 'package:frostdart/frostdart.dart'; +import 'package:frostdart/frostdart_bindings_generated.dart'; +import 'package:frostdart/output.dart'; import 'package:frostdart/util.dart'; abstract class FrostSampleRunner { + static Future runSign() async { + return await compute(_runSign, null); + } + + static String _runSign(int? dummy) { + try { + const network = Network.Regtest; + + final deserializedKeysAlice = deserializeKeys( + keys: + "09000000736563703235366b310100020001003e328d631524f038ab56c2de35" + "a94fb516642098e12e5eef28a07eb5e0d9b682036a7aa3a78f3f5cf6e210" + "9a4885239b97aa945d8c3a4e560ad2067074825122dd036a7aa3a78f3f5c" + "f6e2109a4885239b97aa945d8c3a4e560ad2067074825122dd"); + final deserializedKeysBob = deserializeKeys( + keys: + "09000000736563703235366b310100020002003e328d631524f038ab56c2de35" + "a94fb516642098e12e5eef28a07eb5e0d9b682036a7aa3a78f3f5cf6e210" + "9a4885239b97aa945d8c3a4e560ad2067074825122dd036a7aa3a78f3f5c" + "f6e2109a4885239b97aa945d8c3a4e560ad2067074825122dd"); + + final address = + addressForKeys(network: network, keys: deserializedKeysAlice); + + debugPrint("Address: $address"); + + final signConfigRes = newSignConfig( + network: network, + outputs: [ + Output( + hash: Uint8List.fromList( + hexStringToList( + "1993649f48a6a6053e574c1be9eb607728c6e39b7d3fea2206a2af0f6131c74c", + ), + ), + vout: 1, + value: 200000000, + scriptPubKey: Uint8List.fromList( + hexStringToList( + "5120105968eaa94d798d554d76a381fd65060696c3685ca1434e4d3ba82bd3f5bde0", + ), + ), + ), + ], + paymentAddresses: [ + "bcrt1qdc89v44888fjwus4wke8kppj6043h9698wf8uv", + ], + paymentAmounts: [500000], + change: "bcrt1qdc89v44888fjwus4wke8kppj6043h9698wf8uv", + feePerWeight: 3000, + ); + + debugPrint("created sign config (ptr address = ${signConfigRes.address}"); + + final String encodedConfig = signConfigRes.ref.encoded.toDartString(); + + final signConfig = decodeSignConfig( + network: network, + encodedSignConfig: encodedConfig, + ); + + debugPrint("decoded config finished"); + + final attemptSignResAlice = attemptSign( + thresholdKeysWrapperPointer: deserializedKeysAlice, + signConfigPointer: signConfigRes.ref.config, + ); + final attemptSignResBob = attemptSign( + thresholdKeysWrapperPointer: deserializedKeysBob, + signConfigPointer: signConfig, + ); + debugPrint("attemptSign finished"); + + final alicePre = attemptSignResAlice.ref.preprocess.toDartString(); + debugPrint("alicePre: $alicePre"); + + final bobPre = attemptSignResBob.ref.preprocess.toDartString(); + debugPrint("bobPre: $bobPre"); + + final preprocesses = [ + alicePre, + bobPre, + ]; + debugPrint("preprocesses: $preprocesses"); + + final continueSignResAlice = continueSign( + machine: attemptSignResAlice.ref.machine, + preprocesses: preprocesses, + ); + final continueSignResBob = continueSign( + machine: attemptSignResBob.ref.machine, + preprocesses: preprocesses, + ); + debugPrint("continueSign finished"); + + final contPreAlice = continueSignResAlice.ref.preprocess.toDartString(); + debugPrint("contPreAlice: $contPreAlice"); + final contPreBob = continueSignResBob.ref.preprocess.toDartString(); + debugPrint("contPreBob: $contPreBob"); + + final completeSignResAlice = completeSign( + machine: continueSignResAlice.ref.machine, + shares: [ + contPreAlice, + contPreBob, + ], + ); + final completeSignResBob = completeSign( + machine: continueSignResBob.ref.machine, + shares: [ + contPreAlice, + contPreBob, + ], + ); + debugPrint("completeSign finished"); + + // return "success" or return early with error message string + return "success"; + } catch (e, s) { + debugPrint("run error: $e\n$s"); + return e.toString(); + } + } + static Future runKeygen() async { return await compute(_runKeygen, null); } static String _runKeygen(int? dummy) { try { + const participants = [ + "alice", + "bob", + ]; final sharedMultisigConfig = newMultisigConfig( name: "alice", threshold: 1, - participants: [ - "alice", - "bob", - ], + participants: participants, ); final encodedConfig = sharedMultisigConfig.ref.encoded.toDartString(); @@ -108,6 +235,15 @@ abstract class FrostSampleRunner { return "Recovery strings don't match!"; } + final serializedKeysAlice = + serializeKeys(keys: completeGenAlice.ref.keys); + debugPrint("serializedKeysAlice: $serializedKeysAlice"); + final serializedKeysBob = serializeKeys(keys: completeGenBob.ref.keys); + debugPrint("serializedKeysBob: $serializedKeysBob"); + + debugPrint( + "serializedKeys match: ${serializedKeysBob == serializedKeysAlice}"); + // return "success" or return early with error message string return "success"; } catch (e, s) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 61682dc..6e168c2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -41,7 +41,8 @@ class Content extends StatefulWidget { } class _ContentState extends State { - String? result; + String? resultKeygen; + String? resultSign; late bool enableButton; @@ -54,7 +55,7 @@ class _ContentState extends State { @override Widget build(BuildContext context) { const textStyle = TextStyle(fontSize: 25); - const spacerSmall = SizedBox(height: 30); + const spacerSmall = SizedBox(height: 20); return Container( padding: const EdgeInsets.all(10), child: Column( @@ -62,27 +63,29 @@ class _ContentState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( - onPressed: () async { - setState(() { - enableButton = false; - }); - showDialog( - barrierDismissible: false, - context: context, - builder: (context) => const AlertDialog( - title: Text( - "Running", - ), - ), - ); - result = await FrostSampleRunner.runKeygen(); - if (mounted) { - Navigator.of(context).pop(); - setState(() { - enableButton = true; - }); - } - }, + onPressed: !enableButton + ? null + : () async { + setState(() { + enableButton = false; + }); + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => const AlertDialog( + title: Text( + "Running", + ), + ), + ); + resultKeygen = await FrostSampleRunner.runKeygen(); + if (mounted) { + Navigator.of(context).pop(); + setState(() { + enableButton = true; + }); + } + }, child: const Text( "RUN SIMPLE KEYGEN TEST", style: textStyle, @@ -90,7 +93,45 @@ class _ContentState extends State { ), spacerSmall, Text( - 'Keygen result: ${result.toString()}', + 'Keygen result: $resultKeygen', + style: textStyle, + textAlign: TextAlign.center, + ), + spacerSmall, + spacerSmall, + spacerSmall, + TextButton( + onPressed: enableButton + ? () async { + setState(() { + enableButton = false; + }); + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => const AlertDialog( + title: Text( + "Running", + ), + ), + ); + resultSign = await FrostSampleRunner.runSign(); + if (mounted) { + Navigator.of(context).pop(); + setState(() { + enableButton = true; + }); + } + } + : null, + child: const Text( + "RUN SIMPLE SIGN TEST", + style: textStyle, + ), + ), + spacerSmall, + Text( + 'Sign result: ${resultSign.toString()}', style: textStyle, textAlign: TextAlign.center, ), From a20d47d448638e5e1d0192ba971e81fa63572c1a Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 16:38:04 -0600 Subject: [PATCH 24/49] fix double free --- lib/frostdart.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/frostdart.dart b/lib/frostdart.dart index 9146ccf..cd94872 100644 --- a/lib/frostdart.dart +++ b/lib/frostdart.dart @@ -570,8 +570,6 @@ String completeSign({ shares.length, ); - calloc.free(sharesPointer); - if (result.err != SUCCESS) { throw FrostdartException(errorCode: result.err); } else { From 39f810081cacb223b66ac891f0c37fdf1aef1dbb Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 4 Aug 2023 16:38:35 -0600 Subject: [PATCH 25/49] simple signing example --- example/lib/frost_sample_run.dart | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/example/lib/frost_sample_run.dart b/example/lib/frost_sample_run.dart index f59ee86..8399772 100644 --- a/example/lib/frost_sample_run.dart +++ b/example/lib/frost_sample_run.dart @@ -86,19 +86,19 @@ abstract class FrostSampleRunner { final bobPre = attemptSignResBob.ref.preprocess.toDartString(); debugPrint("bobPre: $bobPre"); - final preprocesses = [ - alicePre, - bobPre, - ]; - debugPrint("preprocesses: $preprocesses"); - final continueSignResAlice = continueSign( machine: attemptSignResAlice.ref.machine, - preprocesses: preprocesses, + preprocesses: [ + "", + bobPre, + ], ); final continueSignResBob = continueSign( machine: attemptSignResBob.ref.machine, - preprocesses: preprocesses, + preprocesses: [ + alicePre, + "", + ], ); debugPrint("continueSign finished"); @@ -110,7 +110,7 @@ abstract class FrostSampleRunner { final completeSignResAlice = completeSign( machine: continueSignResAlice.ref.machine, shares: [ - contPreAlice, + "", contPreBob, ], ); @@ -118,11 +118,17 @@ abstract class FrostSampleRunner { machine: continueSignResBob.ref.machine, shares: [ contPreAlice, - contPreBob, + "", ], ); debugPrint("completeSign finished"); + debugPrint("completeSignResAlice: $completeSignResAlice"); + debugPrint("completeSignResBob: $completeSignResBob"); + + debugPrint( + "completeSignResBob == completeSignResAlice:: ${completeSignResBob == completeSignResAlice}"); + // return "success" or return early with error message string return "success"; } catch (e, s) { From 835c1e404bf57d9021464563334f49420bd9c049 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Aug 2023 10:02:29 -0600 Subject: [PATCH 26/49] update build script to use rust 1.71.0 --- scripts/linux/build_all.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index b86eeb5..cc6ec8d 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -9,10 +9,10 @@ rm -rf "$ROOT_DIR"/src/serai/target cd "$ROOT_DIR"/src/serai/hrf || exit if [ "$IS_ARM" = true ] ; then echo "Building arm frostdart" - cargo build --target aarch64-unknown-linux-gnu --release --lib + cargo +1.71.0 build --target aarch64-unknown-linux-gnu --release --lib cp ../target/aarch64-unknown-linux-gnu/release/libhrf_api.so "$ROOT_DIR"/scripts/linux/build/frostdart.so else echo "Building x86_64 frostdart" - cargo build --target x86_64-unknown-linux-gnu --release --lib + cargo +1.71.0 build --target x86_64-unknown-linux-gnu --release --lib cp ../target/x86_64-unknown-linux-gnu/release/libhrf_api.so "$ROOT_DIR"/scripts/linux/build/frostdart.so fi \ No newline at end of file From 7745395d8bdda90fc2cd382f085df55c5b3a8505 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Aug 2023 12:47:03 -0600 Subject: [PATCH 27/49] android build --- android/build.gradle | 35 ++++++------ .../com/example/frostdart/FrostdartPlugin.kt | 35 ++++++++++++ .../android/app/src/debug/AndroidManifest.xml | 3 +- .../android/app/src/main/AndroidManifest.xml | 3 +- .../app/src/profile/AndroidManifest.xml | 3 +- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + .../contents.xcworkspacedata | 3 ++ scripts/android/.cargo/config | 2 + scripts/android/build_all.sh | 53 +++++++++++++++++++ 10 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 android/src/main/kotlin/com/example/frostdart/FrostdartPlugin.kt create mode 100644 scripts/android/.cargo/config create mode 100755 scripts/android/build_all.sh diff --git a/android/build.gradle b/android/build.gradle index 4ef4c96..c65296e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -4,14 +4,15 @@ group 'com.example.frostdart' version '1.0' buildscript { + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - // The Android Gradle Plugin knows how to build native code with the NDK. classpath 'com.android.tools.build:gradle:7.3.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -23,37 +24,31 @@ rootProject.allprojects { } apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { // Bumping the plugin compileSdkVersion requires all clients of this plugin // to bump the version in their app. compileSdkVersion 31 - // Bumping the plugin ndkVersion requires all clients of this plugin to bump - // the version in their app and to download a newer version of the NDK. - ndkVersion "23.1.7779620" - - // Invoke the shared CMake build with the Android Gradle Plugin. - externalNativeBuild { - cmake { - path "../src/CMakeLists.txt" - - // The default CMake version for the Android Gradle Plugin is 3.10.2. - // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake - // - // The Flutter tooling requires that developers have CMake 3.10 or later - // installed. You should not increase this version, as doing so will cause - // the plugin to fail to compile for some customers of the plugin. - // version "3.10.2" - } - } - compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + defaultConfig { minSdkVersion 16 } } + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/src/main/kotlin/com/example/frostdart/FrostdartPlugin.kt b/android/src/main/kotlin/com/example/frostdart/FrostdartPlugin.kt new file mode 100644 index 0000000..cf19261 --- /dev/null +++ b/android/src/main/kotlin/com/example/frostdart/FrostdartPlugin.kt @@ -0,0 +1,35 @@ +package com.example.flutter_libepiccash + +import androidx.annotation.NonNull + +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result + +/** FlutterLibepiccashPlugin */ +class FrostdartPlugin: FlutterPlugin, MethodCallHandler { + /// The MethodChannel that will the communication between Flutter and native Android + /// + /// This local reference serves to register the plugin with the Flutter Engine and unregister it + /// when the Flutter Engine is detached from the Activity + private lateinit var channel : MethodChannel + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "frostdart") + channel.setMethodCallHandler(this) + } + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + if (call.method == "getPlatformVersion") { + result.success("Android ${android.os.Build.VERSION.RELEASE}") + } else { + result.notImplemented() + } + } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 399f698..ab4c41f 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,4 +1,5 @@ - +