diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..157220d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* linguist-language=rust diff --git a/.github/workflows/dart-integration-test.yml b/.github/workflows/dart-integration-test.yml new file mode 100644 index 0000000..88477b9 --- /dev/null +++ b/.github/workflows/dart-integration-test.yml @@ -0,0 +1,28 @@ +name: Dart Integration Test + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + integration-test: + runs-on: macos-15 + + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + + - run: rustup target add aarch64-apple-ios + + - name: Install FVM + run: | + curl -fsSL https://fvm.app/install.sh | bash + echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH + + - run: cd bindings/dart-bip85 && fvm install + - run: cd bindings/dart-bip85/example && fvm flutter pub get + - run: cd bindings/dart-bip85/example && fvm flutter test integration_test + \ No newline at end of file diff --git a/.github/workflows/precompiled_binaries.yml b/.github/workflows/precompiled_binaries.yml new file mode 100644 index 0000000..294b3bb --- /dev/null +++ b/.github/workflows/precompiled_binaries.yml @@ -0,0 +1,60 @@ +on: + push: + branches: [ master ] + +name: Precompile Binaries +jobs: + Precompile: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macOS-latest + - windows-latest + steps: + - uses: actions/checkout@v4 + - uses: dart-lang/setup-dart@v1 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + + - name: Set RUSTFLAGS for macOS + if: (matrix.os == 'macOS-latest') + run: | + echo "RUSTFLAGS=-C link-arg=-undefined -C link-arg=dynamic_lookup" >> $GITHUB_ENV + echo "MACOSX_DEPLOYMENT_TARGET=17.5" >> $GITHUB_ENV + echo "IPHONEOS_DEPLOYMENT_TARGET=17.5" >> $GITHUB_ENV + + - name: Install Xcode Tools + if: (matrix.os == 'macOS-latest') + run: xcode-select --install || echo "Xcode tools already installed" + + - name: Set up Android SDK + if: (matrix.os == 'ubuntu-latest') + uses: android-actions/setup-android@v3 + + - name: Install Specific NDK + if: (matrix.os == 'ubuntu-latest') + run: sdkmanager --install "ndk;25.1.8937393" + - name: Precompile (with iOS) + if: (matrix.os == 'macOS-latest') + run: dart run build_tool precompile-binaries -v --manifest-dir=../../rust --repository=ethicnology/rust-bip85 + working-directory: bindings/dart-bip85/cargokit/build_tool + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }} + PRIVATE_KEY: ${{ secrets.RELEASE_PRIVATE_KEY }} + + - name: Precompile (with Android) + if: (matrix.os == 'ubuntu-latest') + run: dart run build_tool precompile-binaries -v --manifest-dir=../../rust --repository=ethicnology/rust-bip85 --android-sdk-location=/usr/local/lib/android/sdk --android-ndk-version=25.1.8937393 --android-min-sdk-version=23 + working-directory: bindings/dart-bip85/cargokit/build_tool + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }} + PRIVATE_KEY: ${{ secrets.RELEASE_PRIVATE_KEY }} + diff --git a/.github/workflows/rust-coverage.yml b/.github/workflows/rust-coverage.yml new file mode 100644 index 0000000..29615ec --- /dev/null +++ b/.github/workflows/rust-coverage.yml @@ -0,0 +1,37 @@ +name: Rust Coverage + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + coverage: + runs-on: ubuntu-latest + name: Coverage + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly + components: llvm-tools-preview + + - name: Test + run: cargo test + env: + RUSTFLAGS: "-Cinstrument-coverage" + RUSTDOCFLAGS: "-Cinstrument-coverage" + LLVM_PROFILE_FILE: "${{ github.workspace }}/default_%m_%p.profraw" + + - name: Collect coverage + run: | + curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar -xjf- + ./grcov . --binary-path ./target/debug/deps/ -s . -t lcov --branch --ignore-not-existing --keep-only 'src/*' --ignore '**/tests.rs' -o coverage.lcov + + - name: Submit coverage + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + files: ./coverage.lcov + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 96ef6c0..10597f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +.fvm/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 037da99..dabc8ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,16 @@ [package] -name = "bip85" -version = "0.1.1" -authors = ["Rita Kitic "] +name = "bip85_extended" +version = "1.2.0" +authors = [ + "Rita Kitic ", + "Jules Azad EMERY ", +] description = "BIP-85 - deterministic entropy from bip32 keychains" -repository = "https://github.com/rikitau/rust-bip85" +repository = "https://github.com/ethicnology/rust-bip85" readme = "README.md" license = "MIT" -edition = "2018" +edition = "2021" +keywords = ["bitcoin", "bip", "bip85"] [features] default = ["mnemonic"] @@ -20,6 +24,7 @@ italian = ["mnemonic", "bip39/italian"] japanese = ["mnemonic", "bip39/japanese"] korean = ["mnemonic", "bip39/korean"] spanish = ["mnemonic", "bip39/spanish"] +portuguese = ["mnemonic", "bip39/portuguese"] all-languages = [ "mnemonic", @@ -30,14 +35,17 @@ all-languages = [ "italian", "japanese", "korean", - "spanish" + "spanish", + "portuguese", ] [dependencies] -bitcoin = "0.26.0" -bip39 = { version = "1.0.1", optional = true } +bitcoin = "0.32.4" +bip39 = { version = "2.2.0", optional = true } +sha3 = "0.10.8" +base64 = "0.22.1" +base85 = "2.0.0" [[example]] name = "mnemonic" required-features = ["japanese"] - diff --git a/LICENSE b/LICENSE index e390cc4..24318a7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2020 Rita Kitic +Copyright (c) 2024 Jules Azad EMERY Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 258befe..4efb14b 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,37 @@ -# BIP-85 implementation in Rust +# BIP-85 Deterministic Entropy From BIP32 Keychains -[BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) - deterministic entropy from bip32 keychains. +[![codecov](https://codecov.io/gh/ethicnology/rust-bip85/graph/badge.svg?token=2YN9UI47KT)](https://codecov.io/gh/ethicnology/rust-bip85) -Derives entropy from the extended private key according to -[BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki). +Derives entropy from the extended private key according to [BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki). -Try it [online](https://rikitau.github.io/wasm-bip85/) with WASM magic! +This work is sponsored by [Bull Bitcoin](https://bullbitcoin.com) [Sponsor](https://bullbitcoin.com) -# Examples -There are a few [examples](https://github.com/rikitau/rust-bip85/tree/master/examples) -in the repository. +## Features +- [x] [BIP39 mnemonic](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-BIP39) +- [x] [WIF](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-HDSeed_WIF) +- [x] [XPRV](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-XPRV) +- [x] [HEX](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#hex) +- [x] [DRNG](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#bip85-drng) +- [x] [PWD base64](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-PWD_BASE64) +- [x] [PWD base85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-PWD_BASE85) +- [ ] [DICE](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#user-content-DICE) +- [x] [Nostr](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#nostr) -Running examples: +## Flutter bindings +Thanks to flutter_rust_bridge, I've ported this rust library to [dart-bip85](https://pub.dev/packages/bip85) for flutter applications. + +## Examples +There are a few examples in the `examples/` folder. + +Running examples: ```sh cargo run --example simple ``` @@ -22,7 +40,7 @@ cargo run --example simple cargo run --example mnemonic --features japanese ``` -# Optional features +## Optional features By default the library can derive entropy in any format specified by the standard except mnemonics. To use mnemonics enable feature "mnemonic". diff --git a/bindings/dart-bip85/.fvmrc b/bindings/dart-bip85/.fvmrc new file mode 100644 index 0000000..1efca67 --- /dev/null +++ b/bindings/dart-bip85/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.35.0" +} \ No newline at end of file diff --git a/bindings/dart-bip85/.gitignore b/bindings/dart-bip85/.gitignore new file mode 100644 index 0000000..ac5aa98 --- /dev/null +++ b/bindings/dart-bip85/.gitignore @@ -0,0 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ diff --git a/bindings/dart-bip85/.metadata b/bindings/dart-bip85/.metadata new file mode 100644 index 0000000..d1ab2be --- /dev/null +++ b/bindings/dart-bip85/.metadata @@ -0,0 +1,42 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "603104015dd692ea3403755b55d07813d5cf8965" + channel: "stable" + +project_type: plugin_ffi + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: android + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: ios + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: linux + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: macos + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: windows + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/bindings/dart-bip85/CHANGELOG.md b/bindings/dart-bip85/CHANGELOG.md new file mode 100644 index 0000000..3c0e036 --- /dev/null +++ b/bindings/dart-bip85/CHANGELOG.md @@ -0,0 +1,34 @@ +## 3.0.0 + +- Recommend `bip85_entropy` which is compatible with all platforms (dart native) and is more developers friendly instead of this bindings from rust package `bip85_extended` +- feat: `toMnemonicIn` generates the mnemonic for all the languages available in bip39 spec +- BREAKING CHANGE: `toMnemonic` return the words of the mnemonic as a `List` instead of a `String` this change is justified by the fact that the `rust-bip39` dependency does not use ideographic spaces instead of ASCII space for japanese mnemonic as expected in the specification/test vectors. +- ci: integration test in dart +- refactor: set `fvm` in the repo with flutter `3.35.0` + + + +## 2.0.0 + +- Upgrade: flutter_rust_bridge 2.9.0 + +## 1.0.3 + +- Improve precompiled binaries +- Bindings for PWD64 and PWD85 +- Update docs + +## 1.0.1 + +- Downgrade Flutter_Rust_Bridge version to ^2.0.0 to avoid incompatibility issues with other packages + +## 1.0.2 + +- Publish bip85-extended to crates.io to avoid import issues +- Update readme + +## 1.0.0 + +- Initial version + + diff --git a/bindings/dart-bip85/LICENSE b/bindings/dart-bip85/LICENSE new file mode 100644 index 0000000..3232a02 --- /dev/null +++ b/bindings/dart-bip85/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 J. Azad EMERY a.k.a. ethicnology + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/bindings/dart-bip85/README.md b/bindings/dart-bip85/README.md new file mode 100644 index 0000000..063e435 --- /dev/null +++ b/bindings/dart-bip85/README.md @@ -0,0 +1,175 @@ +# bip85 + +>**We recommend you to use the package [`bip85_entropy`](https://github.com/ethicnology/dart-bip85-entropy) instead of the current `bip85` package** + +> **`bip85_entropy` is written in pure dart, is compatible with all flutter platforms and is more developer friendly** + +> `flutter pub add bip85_entropy` + + The current [bip85](https://github.com/ethicnology/rust-bip85/tree/master/bindings/dart-bip85) package provides Flutter bindings from the rust [bip85_extended](https://github.com/ethicnology/rust-bip85) crate. + + + +This work is sponsored by [Bull Bitcoin](https://bullbitcoin.com) [Sponsor](https://bullbitcoin.com) + + +## Usage + +I recommend checking the `example/` folder which includes a working app at `example/lib/main.dart` as well as integration tests in `example/integration_test/`. + +```dart +import 'package:flutter/material.dart'; +import 'package:bip85/bip85.dart' as bip85; + +Future main() async { + await bip85.LibBip85.init(); // mandatory + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + const xprv = + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"; + + + const language = bip85.Language.english; + var derived = bip85.toMnemonicIn( + xprv: xprv, language: language.label, wordCount: 12, index: 0); + var expected = + "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose"; + assert(derived == expected); + assert(bip85.toMnemonic(xprv: xprv, wordCount: 12, index: 0) == expected); + + var derived = bip85.toMnemonic(xprv: xprv, wordCount: 12, index: 0); + var expected = + "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose"; + assert(derived == expected); + + derived = bip85.toWif(xprv: xprv, index: 0); + expected = "Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp"; + assert(derived == expected); + + derived = bip85.toHex(xprv: xprv, length: 64, index: 0); + expected = + "492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c"; + assert(derived == expected); + + derived = bip85.toXprv(xprv: xprv, index: 0); + expected = + "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX"; + assert(derived == expected); + + derived = bip85.toBase64(xprv: xprv, length: 21, index: 0); + expected = "dKLoepugzdVJvdL56ogNV"; + assert(derived == expected); + + derived = bip85.toBase85(xprv: xprv, length: 12, index: 0); + expected = "_s`{TW89)i4`"; + assert(derived == expected); + + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('flutter_rust_bridge bip85')), + body: Center( + child: Text( + bip85.toMnemonic(xprv: xprv, wordCount: 12, index: 0), + ), + ), + ), + ); + } +} +``` + + +## flutter_rust_bridge documentation + +This project is a starting point for a Flutter +[FFI plugin](https://flutter.dev/to/ffi-package), +a specialized package that includes native code directly invoked with Dart FFI. + +### Project structure + +This template uses the following structure: + +* `src`: Contains the native source code, and a CmakeFile.txt file for building + that source code into a dynamic library. + +* `lib`: Contains the Dart code that defines the API of the plugin, and which + calls into the native code using `dart:ffi`. + +* platform folders (`android`, `ios`, `windows`, etc.): Contains the build files + for building and bundling the native code library with the platform application. + +### Building and bundling native code + +The `pubspec.yaml` specifies FFI plugins as follows: + +```yaml + plugin: + platforms: + some_platform: + ffiPlugin: true +``` + +This configuration invokes the native build for the various target platforms +and bundles the binaries in Flutter applications using these FFI plugins. + +This can be combined with dartPluginClass, such as when FFI is used for the +implementation of one platform in a federated plugin: + +```yaml + plugin: + implements: some_other_plugin + platforms: + some_platform: + dartPluginClass: SomeClass + ffiPlugin: true +``` + +A plugin can have both FFI and method channels: + +```yaml + plugin: + platforms: + some_platform: + pluginClass: SomeName + ffiPlugin: true +``` + +The native build systems that are invoked by FFI (and method channel) plugins are: + +* For Android: Gradle, which invokes the Android NDK for native builds. + * See the documentation in android/build.gradle. +* For iOS and MacOS: Xcode, via CocoaPods. + * See the documentation in ios/bip85.podspec. + * See the documentation in macos/bip85.podspec. +* For Linux and Windows: CMake. + * See the documentation in linux/CMakeLists.txt. + * See the documentation in windows/CMakeLists.txt. + +### Binding to native code + +To use the native code, bindings in Dart are needed. +To avoid writing these by hand, they are generated from the header file +(`src/bip85.h`) by `package:ffigen`. +Regenerate the bindings by running `dart run ffigen --config ffigen.yaml`. + +### Invoking native code + +Very short-running native functions can be directly invoked from any isolate. +For example, see `sum` in `lib/bip85.dart`. + +Longer-running functions should be invoked on a helper isolate to avoid +dropping frames in Flutter applications. +For example, see `sumAsync` in `lib/bip85.dart`. + diff --git a/bindings/dart-bip85/analysis_options.yaml b/bindings/dart-bip85/analysis_options.yaml new file mode 100644 index 0000000..358e9d8 --- /dev/null +++ b/bindings/dart-bip85/analysis_options.yaml @@ -0,0 +1,8 @@ +include: package:lints/recommended.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options +analyzer: + exclude: + - cargokit/ + - lib/src/generated/ \ No newline at end of file diff --git a/bindings/dart-bip85/android/.gitignore b/bindings/dart-bip85/android/.gitignore new file mode 100644 index 0000000..161bdcd --- /dev/null +++ b/bindings/dart-bip85/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/bindings/dart-bip85/android/build.gradle b/bindings/dart-bip85/android/build.gradle new file mode 100644 index 0000000..0ce5452 --- /dev/null +++ b/bindings/dart-bip85/android/build.gradle @@ -0,0 +1,56 @@ +// The Android Gradle Plugin builds the native code with the Android NDK. + +group 'com.flutter_rust_bridge.bip85' +version '1.0' + +buildscript { + 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' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' + +android { + if (project.android.hasProperty("namespace")) { + namespace 'com.flutter_rust_bridge.bip85' + } + + // Bumping the plugin compileSdkVersion requires all clients of this plugin + // to bump the version in their app. + compileSdkVersion 33 + + // Use the NDK version + // declared in /android/app/build.gradle file of the Flutter project. + // Replace it with a version number if this plugin requires a specfic NDK version. + // (e.g. ndkVersion "23.1.7779620") + ndkVersion android.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + } +} + +apply from: "../cargokit/gradle/plugin.gradle" +cargokit { + manifestDir = "../rust" + libname = "bip85" +} diff --git a/bindings/dart-bip85/android/settings.gradle b/bindings/dart-bip85/android/settings.gradle new file mode 100644 index 0000000..9d14da9 --- /dev/null +++ b/bindings/dart-bip85/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'bip85' diff --git a/bindings/dart-bip85/android/src/main/AndroidManifest.xml b/bindings/dart-bip85/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3e2dc5b --- /dev/null +++ b/bindings/dart-bip85/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/bindings/dart-bip85/bullbitcoin.png b/bindings/dart-bip85/bullbitcoin.png new file mode 100644 index 0000000..0fc29c9 Binary files /dev/null and b/bindings/dart-bip85/bullbitcoin.png differ diff --git a/bindings/dart-bip85/cargokit/.gitignore b/bindings/dart-bip85/cargokit/.gitignore new file mode 100644 index 0000000..cf7bb86 --- /dev/null +++ b/bindings/dart-bip85/cargokit/.gitignore @@ -0,0 +1,4 @@ +target +.dart_tool +*.iml +!pubspec.lock diff --git a/bindings/dart-bip85/cargokit/LICENSE b/bindings/dart-bip85/cargokit/LICENSE new file mode 100644 index 0000000..d33a5fe --- /dev/null +++ b/bindings/dart-bip85/cargokit/LICENSE @@ -0,0 +1,42 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Copyright 2022 Matej Knopp + +================================================================================ + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================================================================================ + +APACHE LICENSE, VERSION 2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/bindings/dart-bip85/cargokit/README b/bindings/dart-bip85/cargokit/README new file mode 100644 index 0000000..398474d --- /dev/null +++ b/bindings/dart-bip85/cargokit/README @@ -0,0 +1,11 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +Experimental repository to provide glue for seamlessly integrating cargo build +with flutter plugins and packages. + +See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/ +for a tutorial on how to use Cargokit. + +Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin. + diff --git a/bindings/dart-bip85/cargokit/build_pod.sh b/bindings/dart-bip85/cargokit/build_pod.sh new file mode 100755 index 0000000..ed0e0d9 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_pod.sh @@ -0,0 +1,58 @@ +#!/bin/sh +set -e + +BASEDIR=$(dirname "$0") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +BASEDIR=$(cd "$BASEDIR" ; pwd -P) + +# Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project +NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"` + +export PATH=${NEW_PATH%?} # remove trailing : + +env + +# Platform name (macosx, iphoneos, iphonesimulator) +export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME + +# Arctive architectures (arm64, armv7, x86_64), space separated. +export CARGOKIT_DARWIN_ARCHS=$ARCHS + +# Current build configuration (Debug, Release) +export CARGOKIT_CONFIGURATION=$CONFIGURATION + +# Path to directory containing Cargo.toml. +export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1 + +# Temporary directory for build artifacts. +export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR + +# Output directory for final artifacts. +export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME + +# Directory to store built tool artifacts. +export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool + +# Directory inside root project. Not necessarily the top level directory of root project. +export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT + +FLUTTER_EXPORT_BUILD_ENVIRONMENT=( + "$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS + "$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS +) + +for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}" +do + if [[ -f "$path" ]]; then + source "$path" + fi +done + +sh "$BASEDIR/run_build_tool.sh" build-pod "$@" + +# Make a symlink from built framework to phony file, which will be used as input to +# build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate +# attribute on custom build phase) +ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony" +ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out" diff --git a/bindings/dart-bip85/cargokit/build_tool/README.md b/bindings/dart-bip85/cargokit/build_tool/README.md new file mode 100644 index 0000000..a878c27 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/README.md @@ -0,0 +1,5 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/bindings/dart-bip85/cargokit/build_tool/analysis_options.yaml b/bindings/dart-bip85/cargokit/build_tool/analysis_options.yaml new file mode 100644 index 0000000..0e16a8b --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/analysis_options.yaml @@ -0,0 +1,34 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +linter: + rules: + - prefer_relative_imports + - directives_ordering + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/bindings/dart-bip85/cargokit/build_tool/bin/build_tool.dart b/bindings/dart-bip85/cargokit/build_tool/bin/build_tool.dart new file mode 100644 index 0000000..268eb52 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/bin/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:build_tool/build_tool.dart' as build_tool; + +void main(List arguments) { + build_tool.runMain(arguments); +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/build_tool.dart b/bindings/dart-bip85/cargokit/build_tool/lib/build_tool.dart new file mode 100644 index 0000000..7c1bb75 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/build_tool.dart @@ -0,0 +1,8 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'src/build_tool.dart' as build_tool; + +Future runMain(List args) async { + return build_tool.runMain(args); +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/android_environment.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/android_environment.dart new file mode 100644 index 0000000..15fc9ee --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/android_environment.dart @@ -0,0 +1,195 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' as math; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; +import 'package:version/version.dart'; + +import 'target.dart'; +import 'util.dart'; + +class AndroidEnvironment { + AndroidEnvironment({ + required this.sdkPath, + required this.ndkVersion, + required this.minSdkVersion, + required this.targetTempDir, + required this.target, + }); + + static void clangLinkerWrapper(List args) { + final clang = Platform.environment['_CARGOKIT_NDK_LINK_CLANG']; + if (clang == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_CLANG env var"); + } + final target = Platform.environment['_CARGOKIT_NDK_LINK_TARGET']; + if (target == null) { + throw Exception( + "cargo-ndk rustc linker: didn't find _CARGOKIT_NDK_LINK_TARGET env var"); + } + + runCommand(clang, [ + target, + ...args, + ]); + } + + /// Full path to Android SDK. + final String sdkPath; + + /// Full version of Android NDK. + final String ndkVersion; + + /// Minimum supported SDK version. + final int minSdkVersion; + + /// Target directory for build artifacts. + final String targetTempDir; + + /// Target being built. + final Target target; + + bool ndkIsInstalled() { + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final ndkPackageXml = File(path.join(ndkPath, 'package.xml')); + return ndkPackageXml.existsSync(); + } + + void installNdk({ + required String javaHome, + }) { + final sdkManagerExtension = Platform.isWindows ? '.bat' : ''; + final sdkManager = path.join( + sdkPath, + 'cmdline-tools', + 'latest', + 'bin', + 'sdkmanager$sdkManagerExtension', + ); + + log.info('Installing NDK $ndkVersion'); + runCommand(sdkManager, [ + '--install', + 'ndk;$ndkVersion', + ], environment: { + 'JAVA_HOME': javaHome, + }); + } + + Future> buildEnvironment() async { + final hostArch = Platform.isMacOS + ? "darwin-x86_64" + : (Platform.isLinux ? "linux-x86_64" : "windows-x86_64"); + + final ndkPath = path.join(sdkPath, 'ndk', ndkVersion); + final toolchainPath = path.join( + ndkPath, + 'toolchains', + 'llvm', + 'prebuilt', + hostArch, + 'bin', + ); + + final minSdkVersion = + math.max(target.androidMinSdkVersion!, this.minSdkVersion); + + final exe = Platform.isWindows ? '.exe' : ''; + + final arKey = 'AR_${target.rust}'; + final arValue = ['${target.rust}-ar', 'llvm-ar', 'llvm-ar.exe'] + .map((e) => path.join(toolchainPath, e)) + .firstWhereOrNull((element) => File(element).existsSync()); + if (arValue == null) { + throw Exception('Failed to find ar for $target in $toolchainPath'); + } + + final targetArg = '--target=${target.rust}$minSdkVersion'; + + final ccKey = 'CC_${target.rust}'; + final ccValue = path.join(toolchainPath, 'clang$exe'); + final cfFlagsKey = 'CFLAGS_${target.rust}'; + final cFlagsValue = targetArg; + + final cxxKey = 'CXX_${target.rust}'; + final cxxValue = path.join(toolchainPath, 'clang++$exe'); + final cxxFlagsKey = 'CXXFLAGS_${target.rust}'; + final cxxFlagsValue = targetArg; + + final linkerKey = + 'cargo_target_${target.rust.replaceAll('-', '_')}_linker'.toUpperCase(); + + final ranlibKey = 'RANLIB_${target.rust}'; + final ranlibValue = path.join(toolchainPath, 'llvm-ranlib$exe'); + + final ndkVersionParsed = Version.parse(ndkVersion); + final rustFlagsKey = 'CARGO_ENCODED_RUSTFLAGS'; + final rustFlagsValue = _libGccWorkaround(targetTempDir, ndkVersionParsed); + + final runRustTool = + Platform.isWindows ? 'run_build_tool.cmd' : 'run_build_tool.sh'; + + final packagePath = (await Isolate.resolvePackageUri( + Uri.parse('package:build_tool/buildtool.dart')))! + .toFilePath(); + final selfPath = path.canonicalize(path.join( + packagePath, + '..', + '..', + '..', + runRustTool, + )); + + // Make sure that run_build_tool is working properly even initially launched directly + // through dart run. + final toolTempDir = + Platform.environment['CARGOKIT_TOOL_TEMP_DIR'] ?? targetTempDir; + + return { + arKey: arValue, + ccKey: ccValue, + cfFlagsKey: cFlagsValue, + cxxKey: cxxValue, + cxxFlagsKey: cxxFlagsValue, + ranlibKey: ranlibValue, + rustFlagsKey: rustFlagsValue, + linkerKey: selfPath, + // Recognized by main() so we know when we're acting as a wrapper + '_CARGOKIT_NDK_LINK_TARGET': targetArg, + '_CARGOKIT_NDK_LINK_CLANG': ccValue, + 'CARGOKIT_TOOL_TEMP_DIR': toolTempDir, + }; + } + + // Workaround for libgcc missing in NDK23, inspired by cargo-ndk + String _libGccWorkaround(String buildDir, Version ndkVersion) { + final workaroundDir = path.join( + buildDir, + 'cargokit', + 'libgcc_workaround', + '${ndkVersion.major}', + ); + Directory(workaroundDir).createSync(recursive: true); + if (ndkVersion.major >= 23) { + File(path.join(workaroundDir, 'libgcc.a')) + .writeAsStringSync('INPUT(-lunwind)'); + } else { + // Other way around, untested, forward libgcc.a from libunwind once Rust + // gets updated for NDK23+. + File(path.join(workaroundDir, 'libunwind.a')) + .writeAsStringSync('INPUT(-lgcc)'); + } + + var rustFlags = Platform.environment['CARGO_ENCODED_RUSTFLAGS'] ?? ''; + if (rustFlags.isNotEmpty) { + rustFlags = '$rustFlags\x1f'; + } + rustFlags = '$rustFlags-L\x1f$workaroundDir'; + return rustFlags; + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/artifacts_provider.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/artifacts_provider.dart new file mode 100644 index 0000000..e608cec --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/artifacts_provider.dart @@ -0,0 +1,266 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'builder.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'rustup.dart'; +import 'target.dart'; + +class Artifact { + /// File system location of the artifact. + final String path; + + /// Actual file name that the artifact should have in destination folder. + final String finalFileName; + + AritifactType get type { + if (finalFileName.endsWith('.dll') || + finalFileName.endsWith('.dll.lib') || + finalFileName.endsWith('.pdb') || + finalFileName.endsWith('.so') || + finalFileName.endsWith('.dylib')) { + return AritifactType.dylib; + } else if (finalFileName.endsWith('.lib') || finalFileName.endsWith('.a')) { + return AritifactType.staticlib; + } else { + throw Exception('Unknown artifact type for $finalFileName'); + } + } + + Artifact({ + required this.path, + required this.finalFileName, + }); +} + +final _log = Logger('artifacts_provider'); + +class ArtifactProvider { + ArtifactProvider({ + required this.environment, + required this.userOptions, + }); + + final BuildEnvironment environment; + final CargokitUserOptions userOptions; + + Future>> getArtifacts(List targets) async { + final result = await _getPrecompiledArtifacts(targets); + + final pendingTargets = List.of(targets); + pendingTargets.removeWhere((element) => result.containsKey(element)); + + if (pendingTargets.isEmpty) { + return result; + } + + final rustup = Rustup(); + for (final target in targets) { + final builder = RustBuilder(target: target, environment: environment); + builder.prepare(rustup); + _log.info('Building ${environment.crateInfo.packageName} for $target'); + final targetDir = await builder.build(); + // For local build accept both static and dynamic libraries. + final artifactNames = { + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.dylib, + remote: false, + ), + ...getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + aritifactType: AritifactType.staticlib, + remote: false, + ) + }; + final artifacts = artifactNames + .map((artifactName) => Artifact( + path: path.join(targetDir, artifactName), + finalFileName: artifactName, + )) + .where((element) => File(element.path).existsSync()) + .toList(); + result[target] = artifacts; + } + return result; + } + + Future>> _getPrecompiledArtifacts( + List targets) async { + if (userOptions.usePrecompiledBinaries == false) { + _log.info('Precompiled binaries are disabled'); + return {}; + } + if (environment.crateOptions.precompiledBinaries == null) { + _log.fine('Precompiled binaries not enabled for this crate'); + return {}; + } + + final start = Stopwatch()..start(); + final crateHash = CrateHash.compute(environment.manifestDir, + tempStorage: environment.targetTempDir); + _log.fine( + 'Computed crate hash $crateHash in ${start.elapsedMilliseconds}ms'); + + final downloadedArtifactsDir = + path.join(environment.targetTempDir, 'precompiled', crateHash); + Directory(downloadedArtifactsDir).createSync(recursive: true); + + final res = >{}; + + for (final target in targets) { + final requiredArtifacts = getArtifactNames( + target: target, + libraryName: environment.crateInfo.packageName, + remote: true, + ); + final artifactsForTarget = []; + + for (final artifact in requiredArtifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final downloadedPath = path.join(downloadedArtifactsDir, fileName); + if (!File(downloadedPath).existsSync()) { + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + await _tryDownloadArtifacts( + crateHash: crateHash, + fileName: fileName, + signatureFileName: signatureFileName, + finalPath: downloadedPath, + ); + } + if (File(downloadedPath).existsSync()) { + artifactsForTarget.add(Artifact( + path: downloadedPath, + finalFileName: artifact, + )); + } else { + break; + } + } + + // Only provide complete set of artifacts. + if (artifactsForTarget.length == requiredArtifacts.length) { + _log.fine('Found precompiled artifacts for $target'); + res[target] = artifactsForTarget; + } + } + + return res; + } + + static Future _get(Uri url, {Map? headers}) async { + int attempt = 0; + const maxAttempts = 10; + while (true) { + try { + return await get(url, headers: headers); + } on SocketException catch (e) { + // Try to detect reset by peer error and retry. + if (attempt++ < maxAttempts && + (e.osError?.errorCode == 54 || e.osError?.errorCode == 10054)) { + _log.severe( + 'Failed to download $url: $e, attempt $attempt of $maxAttempts, will retry...'); + await Future.delayed(Duration(seconds: 1)); + continue; + } else { + rethrow; + } + } + } + } + + Future _tryDownloadArtifacts({ + required String crateHash, + required String fileName, + required String signatureFileName, + required String finalPath, + }) async { + final precompiledBinaries = environment.crateOptions.precompiledBinaries!; + final prefix = precompiledBinaries.uriPrefix; + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = Uri.parse('$prefix$crateHash/$signatureFileName'); + _log.fine('Downloading signature from $signatureUrl'); + final signature = await _get(signatureUrl); + if (signature.statusCode == 404) { + _log.warning( + 'Precompiled binaries not available for crate hash $crateHash ($fileName)'); + return; + } + if (signature.statusCode != 200) { + _log.severe( + 'Failed to download signature $signatureUrl: status ${signature.statusCode}'); + return; + } + _log.fine('Downloading binary from $url'); + final res = await _get(url); + if (res.statusCode != 200) { + _log.severe('Failed to download binary $url: status ${res.statusCode}'); + return; + } + if (verify( + precompiledBinaries.publicKey, res.bodyBytes, signature.bodyBytes)) { + File(finalPath).writeAsBytesSync(res.bodyBytes); + } else { + _log.shout('Signature verification failed! Ignoring binary.'); + } + } +} + +enum AritifactType { + staticlib, + dylib, +} + +AritifactType artifactTypeForTarget(Target target) { + if (target.darwinPlatform != null) { + return AritifactType.staticlib; + } else { + return AritifactType.dylib; + } +} + +List getArtifactNames({ + required Target target, + required String libraryName, + required bool remote, + AritifactType? aritifactType, +}) { + aritifactType ??= artifactTypeForTarget(target); + if (target.darwinArch != null) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.dylib']; + } + } else if (target.rust.contains('-windows-')) { + if (aritifactType == AritifactType.staticlib) { + return ['$libraryName.lib']; + } else { + return [ + '$libraryName.dll', + '$libraryName.dll.lib', + if (!remote) '$libraryName.pdb' + ]; + } + } else if (target.rust.contains('-linux-')) { + if (aritifactType == AritifactType.staticlib) { + return ['lib$libraryName.a']; + } else { + return ['lib$libraryName.so']; + } + } else { + throw Exception("Unsupported target: ${target.rust}"); + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/build_cmake.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_cmake.dart new file mode 100644 index 0000000..6f3b2a4 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_cmake.dart @@ -0,0 +1,40 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +class BuildCMake { + final CargokitUserOptions userOptions; + + BuildCMake({required this.userOptions}); + + Future build() async { + final targetPlatform = Environment.targetPlatform; + final target = Target.forFlutterName(Environment.targetPlatform); + if (target == null) { + throw Exception("Unknown target platform: $targetPlatform"); + } + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts([target]); + + final libs = artifacts[target]!; + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path) + .copySync(path.join(Environment.outputDir, lib.finalFileName)); + } + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/build_gradle.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_gradle.dart new file mode 100644 index 0000000..7e61fcb --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_gradle.dart @@ -0,0 +1,49 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; + +final log = Logger('build_gradle'); + +class BuildGradle { + BuildGradle({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.targetPlatforms.map((arch) { + final target = Target.forFlutterName(arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: true); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + for (final target in targets) { + final libs = artifacts[target]!; + final outputDir = path.join(Environment.outputDir, target.android!); + Directory(outputDir).createSync(recursive: true); + + for (final lib in libs) { + if (lib.type == AritifactType.dylib) { + File(lib.path).copySync(path.join(outputDir, lib.finalFileName)); + } + } + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/build_pod.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_pod.dart new file mode 100644 index 0000000..8a9c0db --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_pod.dart @@ -0,0 +1,89 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'target.dart'; +import 'util.dart'; + +class BuildPod { + BuildPod({required this.userOptions}); + + final CargokitUserOptions userOptions; + + Future build() async { + final targets = Environment.darwinArchs.map((arch) { + final target = Target.forDarwin( + platformName: Environment.darwinPlatformName, darwinAarch: arch); + if (target == null) { + throw Exception( + "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); + } + return target; + }).toList(); + + final environment = BuildEnvironment.fromEnvironment(isAndroid: false); + final provider = + ArtifactProvider(environment: environment, userOptions: userOptions); + final artifacts = await provider.getArtifacts(targets); + + void performLipo(String targetFile, Iterable sourceFiles) { + runCommand("lipo", [ + '-create', + ...sourceFiles, + '-output', + targetFile, + ]); + } + + final outputDir = Environment.outputDir; + + Directory(outputDir).createSync(recursive: true); + + final staticLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.staticlib) + .toList(); + final dynamicLibs = artifacts.values + .expand((element) => element) + .where((element) => element.type == AritifactType.dylib) + .toList(); + + final libName = environment.crateInfo.packageName; + + // If there is static lib, use it and link it with pod + if (staticLibs.isNotEmpty) { + final finalTargetFile = path.join(outputDir, "lib$libName.a"); + performLipo(finalTargetFile, staticLibs.map((e) => e.path)); + } else { + // Otherwise try to replace bundle dylib with our dylib + final bundlePaths = [ + '$libName.framework/Versions/A/$libName', + '$libName.framework/$libName', + ]; + + for (final bundlePath in bundlePaths) { + final targetFile = path.join(outputDir, bundlePath); + if (File(targetFile).existsSync()) { + performLipo(targetFile, dynamicLibs.map((e) => e.path)); + + // Replace absolute id with @rpath one so that it works properly + // when moved to Frameworks. + runCommand("install_name_tool", [ + '-id', + '@rpath/$bundlePath', + targetFile, + ]); + return; + } + } + throw Exception('Unable to find bundle for dynamic library'); + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/build_tool.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_tool.dart new file mode 100644 index 0000000..c8f3698 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/build_tool.dart @@ -0,0 +1,271 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; + +import 'android_environment.dart'; +import 'build_cmake.dart'; +import 'build_gradle.dart'; +import 'build_pod.dart'; +import 'logging.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; +import 'util.dart'; +import 'verify_binaries.dart'; + +final log = Logger('build_tool'); + +abstract class BuildCommand extends Command { + Future runBuildCommand(CargokitUserOptions options); + + @override + Future run() async { + final options = CargokitUserOptions.load(); + + if (options.verboseLogging || + Platform.environment['CARGOKIT_VERBOSE'] == '1') { + enableVerboseLogging(); + } + + await runBuildCommand(options); + } +} + +class BuildPodCommand extends BuildCommand { + @override + final name = 'build-pod'; + + @override + final description = 'Build cocoa pod library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildPod(userOptions: options); + await build.build(); + } +} + +class BuildGradleCommand extends BuildCommand { + @override + final name = 'build-gradle'; + + @override + final description = 'Build android library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildGradle(userOptions: options); + await build.build(); + } +} + +class BuildCMakeCommand extends BuildCommand { + @override + final name = 'build-cmake'; + + @override + final description = 'Build CMake library'; + + @override + Future runBuildCommand(CargokitUserOptions options) async { + final build = BuildCMake(userOptions: options); + await build.build(); + } +} + +class GenKeyCommand extends Command { + @override + final name = 'gen-key'; + + @override + final description = 'Generate key pair for signing precompiled binaries'; + + @override + void run() { + final kp = generateKey(); + final private = HEX.encode(kp.privateKey.bytes); + final public = HEX.encode(kp.publicKey.bytes); + print("Private Key: $private"); + print("Public Key: $public"); + } +} + +class PrecompileBinariesCommand extends Command { + PrecompileBinariesCommand() { + argParser + ..addOption( + 'repository', + mandatory: true, + help: 'Github repository slug in format owner/name', + ) + ..addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ) + ..addMultiOption('target', + help: 'Rust target triple of artifact to build.\n' + 'Can be specified multiple times or omitted in which case\n' + 'all targets for current platform will be built.') + ..addOption( + 'android-sdk-location', + help: 'Location of Android SDK (if available)', + ) + ..addOption( + 'android-ndk-version', + help: 'Android NDK version (if available)', + ) + ..addOption( + 'android-min-sdk-version', + help: 'Android minimum rquired version (if available)', + ) + ..addOption( + 'temp-dir', + help: 'Directory to store temporary build artifacts', + ) + ..addFlag( + "verbose", + abbr: "v", + defaultsTo: false, + help: "Enable verbose logging", + ); + } + + @override + final name = 'precompile-binaries'; + + @override + final description = 'Prebuild and upload binaries\n' + 'Private key must be passed through PRIVATE_KEY environment variable. ' + 'Use gen_key through generate priave key.\n' + 'Github token must be passed as GITHUB_TOKEN environment variable.\n'; + + @override + Future run() async { + final verbose = argResults!['verbose'] as bool; + if (verbose) { + enableVerboseLogging(); + } + + final privateKeyString = Platform.environment['PRIVATE_KEY']; + if (privateKeyString == null) { + throw ArgumentError('Missing PRIVATE_KEY environment variable'); + } + final githubToken = Platform.environment['GITHUB_TOKEN']; + if (githubToken == null) { + throw ArgumentError('Missing GITHUB_TOKEN environment variable'); + } + final privateKey = HEX.decode(privateKeyString); + if (privateKey.length != 64) { + throw ArgumentError('Private key must be 64 bytes long'); + } + final manifestDir = argResults!['manifest-dir'] as String; + if (!Directory(manifestDir).existsSync()) { + throw ArgumentError('Manifest directory does not exist: $manifestDir'); + } + String? androidMinSdkVersionString = + argResults!['android-min-sdk-version'] as String?; + int? androidMinSdkVersion; + if (androidMinSdkVersionString != null) { + androidMinSdkVersion = int.tryParse(androidMinSdkVersionString); + if (androidMinSdkVersion == null) { + throw ArgumentError( + 'Invalid android-min-sdk-version: $androidMinSdkVersionString'); + } + } + final targetStrigns = argResults!['target'] as List; + final targets = targetStrigns.map((target) { + final res = Target.forRustTriple(target); + if (res == null) { + throw ArgumentError('Invalid target: $target'); + } + return res; + }).toList(growable: false); + final precompileBinaries = PrecompileBinaries( + privateKey: PrivateKey(privateKey), + githubToken: githubToken, + manifestDir: manifestDir, + repositorySlug: RepositorySlug.full(argResults!['repository'] as String), + targets: targets, + androidSdkLocation: argResults!['android-sdk-location'] as String?, + androidNdkVersion: argResults!['android-ndk-version'] as String?, + androidMinSdkVersion: androidMinSdkVersion, + tempDir: argResults!['temp-dir'] as String?, + ); + + await precompileBinaries.run(); + } +} + +class VerifyBinariesCommand extends Command { + VerifyBinariesCommand() { + argParser.addOption( + 'manifest-dir', + mandatory: true, + help: 'Directory containing Cargo.toml', + ); + } + + @override + final name = "verify-binaries"; + + @override + final description = 'Verifies published binaries\n' + 'Checks whether there is a binary published for each targets\n' + 'and checks the signature.'; + + @override + Future run() async { + final manifestDir = argResults!['manifest-dir'] as String; + final verifyBinaries = VerifyBinaries( + manifestDir: manifestDir, + ); + await verifyBinaries.run(); + } +} + +Future runMain(List args) async { + try { + // Init logging before options are loaded + initLogging(); + + if (Platform.environment['_CARGOKIT_NDK_LINK_TARGET'] != null) { + return AndroidEnvironment.clangLinkerWrapper(args); + } + + final runner = CommandRunner('build_tool', 'Cargokit built_tool') + ..addCommand(BuildPodCommand()) + ..addCommand(BuildGradleCommand()) + ..addCommand(BuildCMakeCommand()) + ..addCommand(GenKeyCommand()) + ..addCommand(PrecompileBinariesCommand()) + ..addCommand(VerifyBinariesCommand()); + + await runner.run(args); + } on ArgumentError catch (e) { + stderr.writeln(e.toString()); + exit(1); + } catch (e, s) { + log.severe(kDoubleSeparator); + log.severe('Cargokit BuildTool failed with error:'); + log.severe(kSeparator); + log.severe(e); + // This tells user to install Rust, there's no need to pollute the log with + // stack trace. + if (e is! RustupNotFoundException) { + log.severe(kSeparator); + log.severe(s); + log.severe(kSeparator); + log.severe('BuildTool arguments: $args'); + } + log.severe(kDoubleSeparator); + exit(1); + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/builder.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/builder.dart new file mode 100644 index 0000000..84c46e4 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/builder.dart @@ -0,0 +1,198 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'package:collection/collection.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'android_environment.dart'; +import 'cargo.dart'; +import 'environment.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; +import 'util.dart'; + +final _log = Logger('builder'); + +enum BuildConfiguration { + debug, + release, + profile, +} + +extension on BuildConfiguration { + bool get isDebug => this == BuildConfiguration.debug; + String get rustName => switch (this) { + BuildConfiguration.debug => 'debug', + BuildConfiguration.release => 'release', + BuildConfiguration.profile => 'release', + }; +} + +class BuildException implements Exception { + final String message; + + BuildException(this.message); + + @override + String toString() { + return 'BuildException: $message'; + } +} + +class BuildEnvironment { + final BuildConfiguration configuration; + final CargokitCrateOptions crateOptions; + final String targetTempDir; + final String manifestDir; + final CrateInfo crateInfo; + + final bool isAndroid; + final String? androidSdkPath; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? javaHome; + + BuildEnvironment({ + required this.configuration, + required this.crateOptions, + required this.targetTempDir, + required this.manifestDir, + required this.crateInfo, + required this.isAndroid, + this.androidSdkPath, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.javaHome, + }); + + static BuildConfiguration parseBuildConfiguration(String value) { + // XCode configuration adds the flavor to configuration name. + final firstSegment = value.split('-').first; + final buildConfiguration = BuildConfiguration.values.firstWhereOrNull( + (e) => e.name == firstSegment, + ); + if (buildConfiguration == null) { + _log.warning('Unknown build configuraiton $value, will assume release'); + return BuildConfiguration.release; + } + return buildConfiguration; + } + + static BuildEnvironment fromEnvironment({ + required bool isAndroid, + }) { + final buildConfiguration = + parseBuildConfiguration(Environment.configuration); + final manifestDir = Environment.manifestDir; + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + final crateInfo = CrateInfo.load(manifestDir); + return BuildEnvironment( + configuration: buildConfiguration, + crateOptions: crateOptions, + targetTempDir: Environment.targetTempDir, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: isAndroid, + androidSdkPath: isAndroid ? Environment.sdkPath : null, + androidNdkVersion: isAndroid ? Environment.ndkVersion : null, + androidMinSdkVersion: + isAndroid ? int.parse(Environment.minSdkVersion) : null, + javaHome: isAndroid ? Environment.javaHome : null, + ); + } +} + +class RustBuilder { + final Target target; + final BuildEnvironment environment; + + RustBuilder({ + required this.target, + required this.environment, + }); + + void prepare( + Rustup rustup, + ) { + final toolchain = _toolchain; + if (rustup.installedTargets(toolchain) == null) { + rustup.installToolchain(toolchain); + } + if (toolchain == 'nightly') { + rustup.installRustSrcForNightly(); + } + if (!rustup.installedTargets(toolchain)!.contains(target.rust)) { + rustup.installTarget(target.rust, toolchain: toolchain); + } + } + + CargoBuildOptions? get _buildOptions => + environment.crateOptions.cargo[environment.configuration]; + + String get _toolchain => _buildOptions?.toolchain.name ?? 'stable'; + + /// Returns the path of directory containing build artifacts. + Future build() async { + final extraArgs = _buildOptions?.flags ?? []; + final manifestPath = path.join(environment.manifestDir, 'Cargo.toml'); + runCommand( + 'rustup', + [ + 'run', + _toolchain, + 'cargo', + 'build', + ...extraArgs, + '--manifest-path', + manifestPath, + '-p', + environment.crateInfo.packageName, + if (!environment.configuration.isDebug) '--release', + '--target', + target.rust, + '--target-dir', + environment.targetTempDir, + ], + environment: await _buildEnvironment(), + ); + return path.join( + environment.targetTempDir, + target.rust, + environment.configuration.rustName, + ); + } + + Future> _buildEnvironment() async { + if (target.android == null) { + return {}; + } else { + final sdkPath = environment.androidSdkPath; + final ndkVersion = environment.androidNdkVersion; + final minSdkVersion = environment.androidMinSdkVersion; + if (sdkPath == null) { + throw BuildException('androidSdkPath is not set'); + } + if (ndkVersion == null) { + throw BuildException('androidNdkVersion is not set'); + } + if (minSdkVersion == null) { + throw BuildException('androidMinSdkVersion is not set'); + } + final env = AndroidEnvironment( + sdkPath: sdkPath, + ndkVersion: ndkVersion, + minSdkVersion: minSdkVersion, + targetTempDir: environment.targetTempDir, + target: target, + ); + if (!env.ndkIsInstalled() && environment.javaHome != null) { + env.installNdk(javaHome: environment.javaHome!); + } + return env.buildEnvironment(); + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/cargo.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/cargo.dart new file mode 100644 index 0000000..0d8958f --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/cargo.dart @@ -0,0 +1,48 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:path/path.dart' as path; +import 'package:toml/toml.dart'; + +class ManifestException { + ManifestException(this.message, {required this.fileName}); + + final String? fileName; + final String message; + + @override + String toString() { + if (fileName != null) { + return 'Failed to parse package manifest at $fileName: $message'; + } else { + return 'Failed to parse package manifest: $message'; + } + } +} + +class CrateInfo { + CrateInfo({required this.packageName}); + + final String packageName; + + static CrateInfo parseManifest(String manifest, {final String? fileName}) { + final toml = TomlDocument.parse(manifest); + final package = toml.toMap()['package']; + if (package == null) { + throw ManifestException('Missing package section', fileName: fileName); + } + final name = package['name']; + if (name == null) { + throw ManifestException('Missing package name', fileName: fileName); + } + return CrateInfo(packageName: name); + } + + static CrateInfo load(String manifestDir) { + final manifestFile = File(path.join(manifestDir, 'Cargo.toml')); + final manifest = manifestFile.readAsStringSync(); + return parseManifest(manifest, fileName: manifestFile.path); + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/crate_hash.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/crate_hash.dart new file mode 100644 index 0000000..0c4d88d --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/crate_hash.dart @@ -0,0 +1,124 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:collection/collection.dart'; +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as path; + +class CrateHash { + /// Computes a hash uniquely identifying crate content. This takes into account + /// content all all .rs files inside the src directory, as well as Cargo.toml, + /// Cargo.lock, build.rs and cargokit.yaml. + /// + /// If [tempStorage] is provided, computed hash is stored in a file in that directory + /// and reused on subsequent calls if the crate content hasn't changed. + static String compute(String manifestDir, {String? tempStorage}) { + return CrateHash._( + manifestDir: manifestDir, + tempStorage: tempStorage, + )._compute(); + } + + CrateHash._({ + required this.manifestDir, + required this.tempStorage, + }); + + String _compute() { + final files = getFiles(); + final tempStorage = this.tempStorage; + if (tempStorage != null) { + final quickHash = _computeQuickHash(files); + final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash')); + quickHashFolder.createSync(recursive: true); + final quickHashFile = File(path.join(quickHashFolder.path, quickHash)); + if (quickHashFile.existsSync()) { + return quickHashFile.readAsStringSync(); + } + final hash = _computeHash(files); + quickHashFile.writeAsStringSync(hash); + return hash; + } else { + return _computeHash(files); + } + } + + /// Computes a quick hash based on files stat (without reading contents). This + /// is used to cache the real hash, which is slower to compute since it involves + /// reading every single file. + String _computeQuickHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + final data = ByteData(8); + for (final file in files) { + input.add(utf8.encode(file.path)); + final stat = file.statSync(); + data.setUint64(0, stat.size); + input.add(data.buffer.asUint8List()); + data.setUint64(0, stat.modified.millisecondsSinceEpoch); + input.add(data.buffer.asUint8List()); + } + + input.close(); + return base64Url.encode(output.events.single.bytes); + } + + String _computeHash(List files) { + final output = AccumulatorSink(); + final input = sha256.startChunkedConversion(output); + + void addTextFile(File file) { + // text Files are hashed by lines in case we're dealing with github checkout + // that auto-converts line endings. + final splitter = LineSplitter(); + if (file.existsSync()) { + final data = file.readAsStringSync(); + final lines = splitter.convert(data); + for (final line in lines) { + input.add(utf8.encode(line)); + } + } + } + + for (final file in files) { + addTextFile(file); + } + + input.close(); + final res = output.events.single; + + // Truncate to 128bits. + final hash = res.bytes.sublist(0, 16); + return hex.encode(hash); + } + + List getFiles() { + final src = Directory(path.join(manifestDir, 'src')); + final files = src + .listSync(recursive: true, followLinks: false) + .whereType() + .toList(); + files.sortBy((element) => element.path); + void addFile(String relative) { + final file = File(path.join(manifestDir, relative)); + if (file.existsSync()) { + files.add(file); + } + } + + addFile('Cargo.toml'); + addFile('Cargo.lock'); + addFile('build.rs'); + addFile('cargokit.yaml'); + return files; + } + + final String manifestDir; + final String? tempStorage; +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/environment.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/environment.dart new file mode 100644 index 0000000..996483a --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/environment.dart @@ -0,0 +1,68 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +extension on String { + String resolveSymlink() => File(this).resolveSymbolicLinksSync(); +} + +class Environment { + /// Current build configuration (debug or release). + static String get configuration => + _getEnv("CARGOKIT_CONFIGURATION").toLowerCase(); + + static bool get isDebug => configuration == 'debug'; + static bool get isRelease => configuration == 'release'; + + /// Temporary directory where Rust build artifacts are placed. + static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR"); + + /// Final output directory where the build artifacts are placed. + static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR'); + + /// Path to the crate manifest (containing Cargo.toml). + static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR'); + + /// Directory inside root project. Not necessarily root folder. Symlinks are + /// not resolved on purpose. + static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR'); + + // Pod + + /// Platform name (macosx, iphoneos, iphonesimulator). + static String get darwinPlatformName => + _getEnv("CARGOKIT_DARWIN_PLATFORM_NAME"); + + /// List of architectures to build for (arm64, armv7, x86_64). + static List get darwinArchs => + _getEnv("CARGOKIT_DARWIN_ARCHS").split(' '); + + // Gradle + static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION"); + static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION"); + static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR"); + static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME"); + static List get targetPlatforms => + _getEnv("CARGOKIT_TARGET_PLATFORMS").split(','); + + // CMAKE + static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM"); + + static String _getEnv(String key) { + final res = Platform.environment[key]; + if (res == null) { + throw Exception("Missing environment variable $key"); + } + return res; + } + + static String _getEnvPath(String key) { + final res = _getEnv(key); + if (Directory(res).existsSync()) { + return res.resolveSymlink(); + } else { + return res; + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/logging.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/logging.dart new file mode 100644 index 0000000..5edd4fd --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/logging.dart @@ -0,0 +1,52 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:logging/logging.dart'; + +const String kSeparator = "--"; +const String kDoubleSeparator = "=="; + +bool _lastMessageWasSeparator = false; + +void _log(LogRecord rec) { + final prefix = '${rec.level.name}: '; + final out = rec.level == Level.SEVERE ? stderr : stdout; + if (rec.message == kSeparator) { + if (!_lastMessageWasSeparator) { + out.write(prefix); + out.writeln('-' * 80); + _lastMessageWasSeparator = true; + } + return; + } else if (rec.message == kDoubleSeparator) { + out.write(prefix); + out.writeln('=' * 80); + _lastMessageWasSeparator = true; + return; + } + out.write(prefix); + out.writeln(rec.message); + _lastMessageWasSeparator = false; +} + +void initLogging() { + Logger.root.level = Level.INFO; + Logger.root.onRecord.listen((LogRecord rec) { + final lines = rec.message.split('\n'); + for (final line in lines) { + if (line.isNotEmpty || lines.length == 1 || line != lines.last) { + _log(LogRecord( + rec.level, + line, + rec.loggerName, + )); + } + } + }); +} + +void enableVerboseLogging() { + Logger.root.level = Level.ALL; +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/options.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/options.dart new file mode 100644 index 0000000..5e9e664 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/options.dart @@ -0,0 +1,312 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:hex/hex.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; +import 'package:source_span/source_span.dart'; +import 'package:yaml/yaml.dart'; + +import 'builder.dart'; +import 'environment.dart'; +import 'rustup.dart'; + +final _log = Logger('options'); + +/// A class for exceptions that have source span information attached. +class SourceSpanException implements Exception { + // This is a getter so that subclasses can override it. + /// A message describing the exception. + String get message => _message; + final String _message; + + // This is a getter so that subclasses can override it. + /// The span associated with this exception. + /// + /// This may be `null` if the source location can't be determined. + SourceSpan? get span => _span; + final SourceSpan? _span; + + SourceSpanException(this._message, this._span); + + /// Returns a string representation of `this`. + /// + /// [color] may either be a [String], a [bool], or `null`. If it's a string, + /// it indicates an ANSI terminal color escape that should be used to + /// highlight the span's text. If it's `true`, it indicates that the text + /// should be highlighted using the default color. If it's `false` or `null`, + /// it indicates that the text shouldn't be highlighted. + @override + String toString({Object? color}) { + if (span == null) return message; + return 'Error on ${span!.message(message, color: color)}'; + } +} + +enum Toolchain { + stable, + beta, + nightly, +} + +class CargoBuildOptions { + final Toolchain toolchain; + final List flags; + + CargoBuildOptions({ + required this.toolchain, + required this.flags, + }); + + static Toolchain _toolchainFromNode(YamlNode node) { + if (node case YamlScalar(value: String name)) { + final toolchain = + Toolchain.values.firstWhereOrNull((element) => element.name == name); + if (toolchain != null) { + return toolchain; + } + } + throw SourceSpanException( + 'Unknown toolchain. Must be one of ${Toolchain.values.map((e) => e.name)}.', + node.span); + } + + static CargoBuildOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + Toolchain toolchain = Toolchain.stable; + List flags = []; + for (final MapEntry(:key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: 'toolchain')) { + toolchain = _toolchainFromNode(value); + } else if (key case YamlScalar(value: 'extra_flags')) { + if (value case YamlList(nodes: List list)) { + if (list.every((element) { + if (element case YamlScalar(value: String _)) { + return true; + } + return false; + })) { + flags = list.map((e) => e.value as String).toList(); + continue; + } + } + throw SourceSpanException( + 'Extra flags must be a list of strings', value.span); + } else { + throw SourceSpanException( + 'Unknown cargo option type. Must be "toolchain" or "extra_flags".', + key.span); + } + } + return CargoBuildOptions(toolchain: toolchain, flags: flags); + } +} + +extension on YamlMap { + /// Map that extracts keys so that we can do map case check on them. + Map get valueMap => + nodes.map((key, value) => MapEntry(key.value, value)); +} + +class PrecompiledBinaries { + final String uriPrefix; + final PublicKey publicKey; + + PrecompiledBinaries({ + required this.uriPrefix, + required this.publicKey, + }); + + static PublicKey _publicKeyFromHex(String key, SourceSpan? span) { + final bytes = HEX.decode(key); + if (bytes.length != 32) { + throw SourceSpanException( + 'Invalid public key. Must be 32 bytes long.', span); + } + return PublicKey(bytes); + } + + static PrecompiledBinaries parse(YamlNode node) { + if (node case YamlMap(valueMap: Map map)) { + if (map + case { + 'url_prefix': YamlNode urlPrefixNode, + 'public_key': YamlNode publicKeyNode, + }) { + final urlPrefix = switch (urlPrefixNode) { + YamlScalar(value: String urlPrefix) => urlPrefix, + _ => throw SourceSpanException( + 'Invalid URL prefix value.', urlPrefixNode.span), + }; + final publicKey = switch (publicKeyNode) { + YamlScalar(value: String publicKey) => + _publicKeyFromHex(publicKey, publicKeyNode.span), + _ => throw SourceSpanException( + 'Invalid public key value.', publicKeyNode.span), + }; + return PrecompiledBinaries( + uriPrefix: urlPrefix, + publicKey: publicKey, + ); + } + } + throw SourceSpanException( + 'Invalid precompiled binaries value. ' + 'Expected Map with "url_prefix" and "public_key".', + node.span); + } +} + +/// Cargokit options specified for Rust crate. +class CargokitCrateOptions { + CargokitCrateOptions({ + this.cargo = const {}, + this.precompiledBinaries, + }); + + final Map cargo; + final PrecompiledBinaries? precompiledBinaries; + + static CargokitCrateOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + final options = {}; + PrecompiledBinaries? precompiledBinaries; + + for (final entry in node.nodes.entries) { + if (entry + case MapEntry( + key: YamlScalar(value: 'cargo'), + value: YamlNode node, + )) { + if (node is! YamlMap) { + throw SourceSpanException('Cargo options must be a map', node.span); + } + for (final MapEntry(:YamlNode key, :value) in node.nodes.entries) { + if (key case YamlScalar(value: String name)) { + final configuration = BuildConfiguration.values + .firstWhereOrNull((element) => element.name == name); + if (configuration != null) { + options[configuration] = CargoBuildOptions.parse(value); + continue; + } + } + throw SourceSpanException( + 'Unknown build configuration. Must be one of ${BuildConfiguration.values.map((e) => e.name)}.', + key.span); + } + } else if (entry.key case YamlScalar(value: 'precompiled_binaries')) { + precompiledBinaries = PrecompiledBinaries.parse(entry.value); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "cargo" or "precompiled_binaries".', + entry.key.span); + } + } + return CargokitCrateOptions( + cargo: options, + precompiledBinaries: precompiledBinaries, + ); + } + + static CargokitCrateOptions load({ + required String manifestDir, + }) { + final uri = Uri.file(path.join(manifestDir, "cargokit.yaml")); + final file = File.fromUri(uri); + if (file.existsSync()) { + final contents = loadYamlNode(file.readAsStringSync(), sourceUrl: uri); + return parse(contents); + } else { + return CargokitCrateOptions(); + } + } +} + +class CargokitUserOptions { + // When Rustup is installed always build locally unless user opts into + // using precompiled binaries. + static bool defaultUsePrecompiledBinaries() { + return Rustup.executablePath() == null; + } + + CargokitUserOptions({ + required this.usePrecompiledBinaries, + required this.verboseLogging, + }); + + CargokitUserOptions._() + : usePrecompiledBinaries = defaultUsePrecompiledBinaries(), + verboseLogging = false; + + static CargokitUserOptions parse(YamlNode node) { + if (node is! YamlMap) { + throw SourceSpanException('Cargokit options must be a map', node.span); + } + bool usePrecompiledBinaries = defaultUsePrecompiledBinaries(); + bool verboseLogging = false; + + for (final entry in node.nodes.entries) { + if (entry.key case YamlScalar(value: 'use_precompiled_binaries')) { + if (entry.value case YamlScalar(value: bool value)) { + usePrecompiledBinaries = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "use_precompiled_binaries". Must be a boolean.', + entry.value.span); + } else if (entry.key case YamlScalar(value: 'verbose_logging')) { + if (entry.value case YamlScalar(value: bool value)) { + verboseLogging = value; + continue; + } + throw SourceSpanException( + 'Invalid value for "verbose_logging". Must be a boolean.', + entry.value.span); + } else { + throw SourceSpanException( + 'Unknown cargokit option type. Must be "use_precompiled_binaries" or "verbose_logging".', + entry.key.span); + } + } + return CargokitUserOptions( + usePrecompiledBinaries: usePrecompiledBinaries, + verboseLogging: verboseLogging, + ); + } + + static CargokitUserOptions load() { + String fileName = "cargokit_options.yaml"; + var userProjectDir = Directory(Environment.rootProjectDir); + + while (userProjectDir.parent.path != userProjectDir.path) { + final configFile = File(path.join(userProjectDir.path, fileName)); + if (configFile.existsSync()) { + final contents = loadYamlNode( + configFile.readAsStringSync(), + sourceUrl: configFile.uri, + ); + final res = parse(contents); + if (res.verboseLogging) { + _log.info('Found user options file at ${configFile.path}'); + } + return res; + } + userProjectDir = userProjectDir.parent; + } + return CargokitUserOptions( + usePrecompiledBinaries: true, + verboseLogging: false, + ); + } + + final bool usePrecompiledBinaries; + final bool verboseLogging; +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/precompile_binaries.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/precompile_binaries.dart new file mode 100644 index 0000000..c27f419 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/precompile_binaries.dart @@ -0,0 +1,202 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:github/github.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'artifacts_provider.dart'; +import 'builder.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'rustup.dart'; +import 'target.dart'; + +final _log = Logger('precompile_binaries'); + +class PrecompileBinaries { + PrecompileBinaries({ + required this.privateKey, + required this.githubToken, + required this.repositorySlug, + required this.manifestDir, + required this.targets, + this.androidSdkLocation, + this.androidNdkVersion, + this.androidMinSdkVersion, + this.tempDir, + }); + + final PrivateKey privateKey; + final String githubToken; + final RepositorySlug repositorySlug; + final String manifestDir; + final List targets; + final String? androidSdkLocation; + final String? androidNdkVersion; + final int? androidMinSdkVersion; + final String? tempDir; + + static String fileName(Target target, String name) { + return '${target.rust}_$name'; + } + + static String signatureFileName(Target target, String name) { + return '${target.rust}_$name.sig'; + } + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final targets = List.of(this.targets); + if (targets.isEmpty) { + targets.addAll([ + ...Target.buildableTargets(), + if (androidSdkLocation != null) ...Target.androidTargets(), + ]); + } + + _log.info('Precompiling binaries for $targets'); + + final hash = CrateHash.compute(manifestDir); + _log.info('Computed crate hash: $hash'); + + final String tagName = 'precompiled_$hash'; + + final github = GitHub(auth: Authentication.withToken(githubToken)); + final repo = github.repositories; + final release = await _getOrCreateRelease( + repo: repo, + tagName: tagName, + packageName: crateInfo.packageName, + hash: hash, + ); + + final tempDir = this.tempDir != null + ? Directory(this.tempDir!) + : Directory.systemTemp.createTempSync('precompiled_'); + + tempDir.createSync(recursive: true); + + final crateOptions = CargokitCrateOptions.load( + manifestDir: manifestDir, + ); + + final buildEnvironment = BuildEnvironment( + configuration: BuildConfiguration.release, + crateOptions: crateOptions, + targetTempDir: tempDir.path, + manifestDir: manifestDir, + crateInfo: crateInfo, + isAndroid: androidSdkLocation != null, + androidSdkPath: androidSdkLocation, + androidNdkVersion: androidNdkVersion, + androidMinSdkVersion: androidMinSdkVersion, + ); + + final rustup = Rustup(); + + for (final target in targets) { + final artifactNames = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + if (artifactNames.every((name) { + final fileName = PrecompileBinaries.fileName(target, name); + return (release.assets ?? []).any((e) => e.name == fileName); + })) { + _log.info("All artifacts for $target already exist - skipping"); + continue; + } + + _log.info('Building for $target'); + + final builder = + RustBuilder(target: target, environment: buildEnvironment); + builder.prepare(rustup); + final res = await builder.build(); + + final assets = []; + for (final name in artifactNames) { + final file = File(path.join(res, name)); + if (!file.existsSync()) { + throw Exception('Missing artifact: ${file.path}'); + } + + final data = file.readAsBytesSync(); + final create = CreateReleaseAsset( + name: PrecompileBinaries.fileName(target, name), + contentType: "application/octet-stream", + assetData: data, + ); + final signature = sign(privateKey, data); + final signatureCreate = CreateReleaseAsset( + name: signatureFileName(target, name), + contentType: "application/octet-stream", + assetData: signature, + ); + bool verified = verify(public(privateKey), data, signature); + if (!verified) { + throw Exception('Signature verification failed'); + } + assets.add(create); + assets.add(signatureCreate); + } + _log.info('Uploading assets: ${assets.map((e) => e.name)}'); + for (final asset in assets) { + // This seems to be failing on CI so do it one by one + int retryCount = 0; + while (true) { + try { + await repo.uploadReleaseAssets(release, [asset]); + break; + } on Exception catch (e) { + if (retryCount == 10) { + rethrow; + } + ++retryCount; + _log.shout( + 'Upload failed (attempt $retryCount, will retry): ${e.toString()}'); + await Future.delayed(Duration(seconds: 2)); + } + } + } + } + + _log.info('Cleaning up'); + tempDir.deleteSync(recursive: true); + } + + Future _getOrCreateRelease({ + required RepositoriesService repo, + required String tagName, + required String packageName, + required String hash, + }) async { + Release release; + try { + _log.info('Fetching release $tagName'); + release = await repo.getReleaseByTagName(repositorySlug, tagName); + } on ReleaseNotFound { + _log.info('Release not found - creating release $tagName'); + release = await repo.createRelease( + repositorySlug, + CreateRelease.from( + tagName: tagName, + name: 'Precompiled binaries ${hash.substring(0, 8)}', + targetCommitish: null, + isDraft: false, + isPrerelease: false, + body: 'Precompiled binaries for crate $packageName, ' + 'crate hash $hash.', + )); + } + return release; + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/rustup.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/rustup.dart new file mode 100644 index 0000000..0ac8d08 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/rustup.dart @@ -0,0 +1,136 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as path; + +import 'util.dart'; + +class _Toolchain { + _Toolchain( + this.name, + this.targets, + ); + + final String name; + final List targets; +} + +class Rustup { + List? installedTargets(String toolchain) { + final targets = _installedTargets(toolchain); + return targets != null ? List.unmodifiable(targets) : null; + } + + void installToolchain(String toolchain) { + log.info("Installing Rust toolchain: $toolchain"); + runCommand("rustup", ['toolchain', 'install', toolchain]); + _installedToolchains + .add(_Toolchain(toolchain, _getInstalledTargets(toolchain))); + } + + void installTarget( + String target, { + required String toolchain, + }) { + log.info("Installing Rust target: $target"); + runCommand("rustup", [ + 'target', + 'add', + '--toolchain', + toolchain, + target, + ]); + _installedTargets(toolchain)?.add(target); + } + + final List<_Toolchain> _installedToolchains; + + Rustup() : _installedToolchains = _getInstalledToolchains(); + + List? _installedTargets(String toolchain) => _installedToolchains + .firstWhereOrNull( + (e) => e.name == toolchain || e.name.startsWith('$toolchain-')) + ?.targets; + + static List<_Toolchain> _getInstalledToolchains() { + String extractToolchainName(String line) { + // ignore (default) after toolchain name + final parts = line.split(' '); + return parts[0]; + } + + final res = runCommand("rustup", ['toolchain', 'list']); + + // To list all non-custom toolchains, we need to filter out lines that + // don't start with "stable", "beta", or "nightly". + Pattern nonCustom = RegExp(r"^(stable|beta|nightly)"); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty && e.startsWith(nonCustom)) + .map(extractToolchainName) + .toList(growable: true); + + return lines + .map( + (name) => _Toolchain( + name, + _getInstalledTargets(name), + ), + ) + .toList(growable: true); + } + + static List _getInstalledTargets(String toolchain) { + final res = runCommand("rustup", [ + 'target', + 'list', + '--toolchain', + toolchain, + '--installed', + ]); + final lines = res.stdout + .toString() + .split('\n') + .where((e) => e.isNotEmpty) + .toList(growable: true); + return lines; + } + + bool _didInstallRustSrcForNightly = false; + + void installRustSrcForNightly() { + if (_didInstallRustSrcForNightly) { + return; + } + // Useful for -Z build-std + runCommand( + "rustup", + ['component', 'add', 'rust-src', '--toolchain', 'nightly'], + ); + _didInstallRustSrcForNightly = true; + } + + static String? executablePath() { + final envPath = Platform.environment['PATH']; + final envPathSeparator = Platform.isWindows ? ';' : ':'; + final home = Platform.isWindows + ? Platform.environment['USERPROFILE'] + : Platform.environment['HOME']; + final paths = [ + if (home != null) path.join(home, '.cargo', 'bin'), + if (envPath != null) ...envPath.split(envPathSeparator), + ]; + for (final p in paths) { + final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup'; + final rustupPath = path.join(p, rustup); + if (File(rustupPath).existsSync()) { + return rustupPath; + } + } + return null; + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/target.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/target.dart new file mode 100644 index 0000000..6fbc58b --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/target.dart @@ -0,0 +1,140 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:collection/collection.dart'; + +import 'util.dart'; + +class Target { + Target({ + required this.rust, + this.flutter, + this.android, + this.androidMinSdkVersion, + this.darwinPlatform, + this.darwinArch, + }); + + static final all = [ + Target( + rust: 'armv7-linux-androideabi', + flutter: 'android-arm', + android: 'armeabi-v7a', + androidMinSdkVersion: 16, + ), + Target( + rust: 'aarch64-linux-android', + flutter: 'android-arm64', + android: 'arm64-v8a', + androidMinSdkVersion: 21, + ), + Target( + rust: 'i686-linux-android', + flutter: 'android-x86', + android: 'x86', + androidMinSdkVersion: 16, + ), + Target( + rust: 'x86_64-linux-android', + flutter: 'android-x64', + android: 'x86_64', + androidMinSdkVersion: 21, + ), + Target( + rust: 'x86_64-pc-windows-msvc', + flutter: 'windows-x64', + ), + Target( + rust: 'x86_64-unknown-linux-gnu', + flutter: 'linux-x64', + ), + Target( + rust: 'aarch64-unknown-linux-gnu', + flutter: 'linux-arm64', + ), + Target( + rust: 'x86_64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'x86_64', + ), + Target( + rust: 'aarch64-apple-darwin', + darwinPlatform: 'macosx', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios', + darwinPlatform: 'iphoneos', + darwinArch: 'arm64', + ), + Target( + rust: 'aarch64-apple-ios-sim', + darwinPlatform: 'iphonesimulator', + darwinArch: 'arm64', + ), + Target( + rust: 'x86_64-apple-ios', + darwinPlatform: 'iphonesimulator', + darwinArch: 'x86_64', + ), + ]; + + static Target? forFlutterName(String flutterName) { + return all.firstWhereOrNull((element) => element.flutter == flutterName); + } + + static Target? forDarwin({ + required String platformName, + required String darwinAarch, + }) { + return all.firstWhereOrNull((element) => // + element.darwinPlatform == platformName && + element.darwinArch == darwinAarch); + } + + static Target? forRustTriple(String triple) { + return all.firstWhereOrNull((element) => element.rust == triple); + } + + static List androidTargets() { + return all + .where((element) => element.android != null) + .toList(growable: false); + } + + /// Returns buildable targets on current host platform ignoring Android targets. + static List buildableTargets() { + if (Platform.isLinux) { + // Right now we don't support cross-compiling on Linux. So we just return + // the host target. + final arch = runCommand('arch', []).stdout as String; + if (arch.trim() == 'aarch64') { + return [Target.forRustTriple('aarch64-unknown-linux-gnu')!]; + } else { + return [Target.forRustTriple('x86_64-unknown-linux-gnu')!]; + } + } + return all.where((target) { + if (Platform.isWindows) { + return target.rust.contains('-windows-'); + } else if (Platform.isMacOS) { + return target.darwinPlatform != null; + } + return false; + }).toList(growable: false); + } + + @override + String toString() { + return rust; + } + + final String? flutter; + final String rust; + final String? android; + final int? androidMinSdkVersion; + final String? darwinPlatform; + final String? darwinArch; +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/util.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/util.dart new file mode 100644 index 0000000..8bb6a87 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/util.dart @@ -0,0 +1,172 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:convert'; +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'logging.dart'; +import 'rustup.dart'; + +final log = Logger("process"); + +class CommandFailedException implements Exception { + final String executable; + final List arguments; + final ProcessResult result; + + CommandFailedException({ + required this.executable, + required this.arguments, + required this.result, + }); + + @override + String toString() { + final stdout = result.stdout.toString().trim(); + final stderr = result.stderr.toString().trim(); + return [ + "External Command: $executable ${arguments.map((e) => '"$e"').join(' ')}", + "Returned Exit Code: ${result.exitCode}", + kSeparator, + "STDOUT:", + if (stdout.isNotEmpty) stdout, + kSeparator, + "STDERR:", + if (stderr.isNotEmpty) stderr, + ].join('\n'); + } +} + +class TestRunCommandArgs { + final String executable; + final List arguments; + final String? workingDirectory; + final Map? environment; + final bool includeParentEnvironment; + final bool runInShell; + final Encoding? stdoutEncoding; + final Encoding? stderrEncoding; + + TestRunCommandArgs({ + required this.executable, + required this.arguments, + this.workingDirectory, + this.environment, + this.includeParentEnvironment = true, + this.runInShell = false, + this.stdoutEncoding, + this.stderrEncoding, + }); +} + +class TestRunCommandResult { + TestRunCommandResult({ + this.pid = 1, + this.exitCode = 0, + this.stdout = '', + this.stderr = '', + }); + + final int pid; + final int exitCode; + final String stdout; + final String stderr; +} + +TestRunCommandResult Function(TestRunCommandArgs args)? testRunCommandOverride; + +ProcessResult runCommand( + String executable, + List arguments, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, +}) { + if (testRunCommandOverride != null) { + final result = testRunCommandOverride!(TestRunCommandArgs( + executable: executable, + arguments: arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + )); + return ProcessResult( + result.pid, + result.exitCode, + result.stdout, + result.stderr, + ); + } + log.finer('Running command $executable ${arguments.join(' ')}'); + final res = Process.runSync( + _resolveExecutable(executable), + arguments, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stderrEncoding: stderrEncoding, + stdoutEncoding: stdoutEncoding, + ); + if (res.exitCode != 0) { + throw CommandFailedException( + executable: executable, + arguments: arguments, + result: res, + ); + } else { + return res; + } +} + +class RustupNotFoundException implements Exception { + @override + String toString() { + return [ + ' ', + 'rustup not found in PATH.', + ' ', + 'Maybe you need to install Rust? It only takes a minute:', + ' ', + if (Platform.isWindows) 'https://www.rust-lang.org/tools/install', + if (hasHomebrewRustInPath()) ...[ + '\$ brew unlink rust # Unlink homebrew Rust from PATH', + ], + if (!Platform.isWindows) + "\$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh", + ' ', + ].join('\n'); + } + + static bool hasHomebrewRustInPath() { + if (!Platform.isMacOS) { + return false; + } + final envPath = Platform.environment['PATH'] ?? ''; + final paths = envPath.split(':'); + return paths.any((p) { + return p.contains('homebrew') && File(path.join(p, 'rustc')).existsSync(); + }); + } +} + +String _resolveExecutable(String executable) { + if (executable == 'rustup') { + final resolved = Rustup.executablePath(); + if (resolved != null) { + return resolved; + } + throw RustupNotFoundException(); + } else { + return executable; + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/lib/src/verify_binaries.dart b/bindings/dart-bip85/cargokit/build_tool/lib/src/verify_binaries.dart new file mode 100644 index 0000000..2366b57 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/lib/src/verify_binaries.dart @@ -0,0 +1,84 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import 'dart:io'; + +import 'package:ed25519_edwards/ed25519_edwards.dart'; +import 'package:http/http.dart'; + +import 'artifacts_provider.dart'; +import 'cargo.dart'; +import 'crate_hash.dart'; +import 'options.dart'; +import 'precompile_binaries.dart'; +import 'target.dart'; + +class VerifyBinaries { + VerifyBinaries({ + required this.manifestDir, + }); + + final String manifestDir; + + Future run() async { + final crateInfo = CrateInfo.load(manifestDir); + + final config = CargokitCrateOptions.load(manifestDir: manifestDir); + final precompiledBinaries = config.precompiledBinaries; + if (precompiledBinaries == null) { + stdout.writeln('Crate does not support precompiled binaries.'); + } else { + final crateHash = CrateHash.compute(manifestDir); + stdout.writeln('Crate hash: $crateHash'); + + for (final target in Target.all) { + final message = 'Checking ${target.rust}...'; + stdout.write(message.padRight(40)); + stdout.flush(); + + final artifacts = getArtifactNames( + target: target, + libraryName: crateInfo.packageName, + remote: true, + ); + + final prefix = precompiledBinaries.uriPrefix; + + bool ok = true; + + for (final artifact in artifacts) { + final fileName = PrecompileBinaries.fileName(target, artifact); + final signatureFileName = + PrecompileBinaries.signatureFileName(target, artifact); + + final url = Uri.parse('$prefix$crateHash/$fileName'); + final signatureUrl = + Uri.parse('$prefix$crateHash/$signatureFileName'); + + final signature = await get(signatureUrl); + if (signature.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + final asset = await get(url); + if (asset.statusCode != 200) { + stdout.writeln('MISSING'); + ok = false; + break; + } + + if (!verify(precompiledBinaries.publicKey, asset.bodyBytes, + signature.bodyBytes)) { + stdout.writeln('INVALID SIGNATURE'); + ok = false; + } + } + + if (ok) { + stdout.writeln('OK'); + } + } + } + } +} diff --git a/bindings/dart-bip85/cargokit/build_tool/pubspec.lock b/bindings/dart-bip85/cargokit/build_tool/pubspec.lock new file mode 100644 index 0000000..343bdd3 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/pubspec.lock @@ -0,0 +1,453 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + args: + dependency: "direct main" + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: "direct main" + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + ed25519_edwards: + dependency: "direct main" + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + github: + dependency: "direct main" + description: + name: github + sha256: "9966bc13bf612342e916b0a343e95e5f046c88f602a14476440e9b75d2295411" + url: "https://pub.dev" + source: hosted + version: "9.17.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hex: + dependency: "direct main" + description: + name: hex + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: "direct main" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "9b0dd8e36af4a5b1569029949d50a52cb2a2a2fdaa20cebb96e6603b9ae241f9" + url: "https://pub.dev" + source: hosted + version: "1.24.6" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: "4bef837e56375537055fdbbbf6dd458b1859881f4c7e6da936158f77d61ab265" + url: "https://pub.dev" + source: hosted + version: "0.5.6" + toml: + dependency: "direct main" + description: + name: toml + sha256: "157c5dca5160fced243f3ce984117f729c788bb5e475504f3dbcda881accee44" + url: "https://pub.dev" + source: hosted + version: "0.14.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + version: + dependency: "direct main" + description: + name: version + sha256: "2307e23a45b43f96469eeab946208ed63293e8afca9c28cd8b5241ff31c55f55" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0fae432c85c4ea880b33b497d32824b97795b04cdaa74d270219572a1f50268d" + url: "https://pub.dev" + source: hosted + version: "11.9.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.0.0 <4.0.0" diff --git a/bindings/dart-bip85/cargokit/build_tool/pubspec.yaml b/bindings/dart-bip85/cargokit/build_tool/pubspec.yaml new file mode 100644 index 0000000..18c61e3 --- /dev/null +++ b/bindings/dart-bip85/cargokit/build_tool/pubspec.yaml @@ -0,0 +1,33 @@ +# This is copied from Cargokit (which is the official way to use it currently) +# Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +name: build_tool +description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build. +publish_to: none +version: 1.0.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + +# Add regular dependencies here. +dependencies: + # these are pinned on purpose because the bundle_tool_runner doesn't have + # pubspec.lock. See run_build_tool.sh + logging: 1.2.0 + path: 1.8.0 + version: 3.0.0 + collection: 1.18.0 + ed25519_edwards: 0.3.1 + hex: 0.2.0 + yaml: 3.1.2 + source_span: 1.10.0 + github: 9.17.0 + args: 2.4.2 + crypto: 3.0.3 + convert: 3.1.1 + http: 1.1.0 + toml: 0.14.0 + +dev_dependencies: + lints: ^2.1.0 + test: ^1.24.0 diff --git a/bindings/dart-bip85/cargokit/cmake/cargokit.cmake b/bindings/dart-bip85/cargokit/cmake/cargokit.cmake new file mode 100644 index 0000000..ddd05df --- /dev/null +++ b/bindings/dart-bip85/cargokit/cmake/cargokit.cmake @@ -0,0 +1,99 @@ +SET(cargokit_cmake_root "${CMAKE_CURRENT_LIST_DIR}/..") + +# Workaround for https://github.com/dart-lang/pub/issues/4010 +get_filename_component(cargokit_cmake_root "${cargokit_cmake_root}" REALPATH) + +if(WIN32) + # REALPATH does not properly resolve symlinks on windows :-/ + execute_process(COMMAND powershell -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1" "${cargokit_cmake_root}" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Arguments +# - target: CMAKE target to which rust library is linked +# - manifest_dir: relative path from current folder to directory containing cargo manifest +# - lib_name: cargo package name +# - any_symbol_name: name of any exported symbol from the library. +# used on windows to force linking with library. +function(apply_cargokit target manifest_dir lib_name any_symbol_name) + + set(CARGOKIT_LIB_NAME "${lib_name}") + set(CARGOKIT_LIB_FULL_NAME "${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}") + if (CMAKE_CONFIGURATION_TYPES) + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/$/${CARGOKIT_LIB_FULL_NAME}") + else() + set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}") + endif() + set(CARGOKIT_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/cargokit_build") + + if (FLUTTER_TARGET_PLATFORM) + set(CARGOKIT_TARGET_PLATFORM "${FLUTTER_TARGET_PLATFORM}") + else() + set(CARGOKIT_TARGET_PLATFORM "windows-x64") + endif() + + set(CARGOKIT_ENV + "CARGOKIT_CMAKE=${CMAKE_COMMAND}" + "CARGOKIT_CONFIGURATION=$" + "CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}" + "CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}" + "CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}" + "CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}" + "CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool" + "CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}" + ) + + if (WIN32) + set(SCRIPT_EXTENSION ".cmd") + set(IMPORT_LIB_EXTENSION ".lib") + else() + set(SCRIPT_EXTENSION ".sh") + set(IMPORT_LIB_EXTENSION "") + execute_process(COMMAND chmod +x "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}") + endif() + + # Using generators in custom command is only supported in CMake 3.20+ + if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS "3.20.0") + foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES) + add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}" + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endforeach() + else() + add_custom_command( + OUTPUT + ${OUTPUT_LIB} + "${CMAKE_CURRENT_BINARY_DIR}/_phony_" + COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} + "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake + VERBATIM + ) + endif() + + + set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/_phony_" PROPERTIES SYMBOLIC TRUE) + + if (TARGET ${target}) + # If we have actual cmake target provided create target and make existing + # target depend on it + add_custom_target("${target}_cargokit" DEPENDS ${OUTPUT_LIB}) + add_dependencies("${target}" "${target}_cargokit") + target_link_libraries("${target}" PRIVATE "${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}") + if(WIN32) + target_link_options(${target} PRIVATE "/INCLUDE:${any_symbol_name}") + endif() + else() + # Otherwise (FFI) just use ALL to force building always + add_custom_target("${target}_cargokit" ALL DEPENDS ${OUTPUT_LIB}) + endif() + + # Allow adding the output library to plugin bundled libraries + set("${target}_cargokit_lib" ${OUTPUT_LIB} PARENT_SCOPE) + +endfunction() diff --git a/bindings/dart-bip85/cargokit/cmake/resolve_symlinks.ps1 b/bindings/dart-bip85/cargokit/cmake/resolve_symlinks.ps1 new file mode 100644 index 0000000..3d10d28 --- /dev/null +++ b/bindings/dart-bip85/cargokit/cmake/resolve_symlinks.ps1 @@ -0,0 +1,27 @@ +function Resolve-Symlinks { + [CmdletBinding()] + [OutputType([string])] + param( + [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [string] $Path + ) + + [string] $separator = '/' + [string[]] $parts = $Path.Split($separator) + + [string] $realPath = '' + foreach ($part in $parts) { + if ($realPath -and !$realPath.EndsWith($separator)) { + $realPath += $separator + } + $realPath += $part + $item = Get-Item $realPath + if ($item.Target) { + $realPath = $item.Target.Replace('\', '/') + } + } + $realPath +} + +$path=Resolve-Symlinks -Path $args[0] +Write-Host $path diff --git a/bindings/dart-bip85/cargokit/gradle/plugin.gradle b/bindings/dart-bip85/cargokit/gradle/plugin.gradle new file mode 100644 index 0000000..1aead89 --- /dev/null +++ b/bindings/dart-bip85/cargokit/gradle/plugin.gradle @@ -0,0 +1,179 @@ +/// This is copied from Cargokit (which is the official way to use it currently) +/// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin + +import java.nio.file.Paths +import org.apache.tools.ant.taskdefs.condition.Os + +CargoKitPlugin.file = buildscript.sourceFile + +apply plugin: CargoKitPlugin + +class CargoKitExtension { + String manifestDir; // Relative path to folder containing Cargo.toml + String libname; // Library name within Cargo.toml. Must be a cdylib +} + +abstract class CargoKitBuildTask extends DefaultTask { + + @Input + String buildMode + + @Input + String buildDir + + @Input + String outputDir + + @Input + String ndkVersion + + @Input + String sdkDirectory + + @Input + int compileSdkVersion; + + @Input + int minSdkVersion; + + @Input + String pluginFile + + @Input + List targetPlatforms + + @TaskAction + def build() { + if (project.cargokit.manifestDir == null) { + throw new GradleException("Property 'manifestDir' must be set on cargokit extension"); + } + + if (project.cargokit.libname == null) { + throw new GradleException("Property 'libname' must be set on cargokit extension"); + } + + def executableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "run_build_tool.cmd" : "run_build_tool.sh" + def path = Paths.get(new File(pluginFile).parent, "..", executableName); + + def manifestDir = Paths.get(project.buildscript.sourceFile.parent, project.cargokit.manifestDir) + + def rootProjectDir = project.rootProject.projectDir + + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + project.exec { + commandLine 'chmod', '+x', path + } + } + + project.exec { + executable path + args "build-gradle" + environment "CARGOKIT_ROOT_PROJECT_DIR", rootProjectDir + environment "CARGOKIT_TOOL_TEMP_DIR", "${buildDir}/build_tool" + environment "CARGOKIT_MANIFEST_DIR", manifestDir + environment "CARGOKIT_CONFIGURATION", buildMode + environment "CARGOKIT_TARGET_TEMP_DIR", buildDir + environment "CARGOKIT_OUTPUT_DIR", outputDir + environment "CARGOKIT_NDK_VERSION", ndkVersion + environment "CARGOKIT_SDK_DIR", sdkDirectory + environment "CARGOKIT_COMPILE_SDK_VERSION", compileSdkVersion + environment "CARGOKIT_MIN_SDK_VERSION", minSdkVersion + environment "CARGOKIT_TARGET_PLATFORMS", targetPlatforms.join(",") + environment "CARGOKIT_JAVA_HOME", System.properties['java.home'] + } + } +} + +class CargoKitPlugin implements Plugin { + + static String file; + + private Plugin findFlutterPlugin(Project rootProject) { + _findFlutterPlugin(rootProject.childProjects) + } + + private Plugin _findFlutterPlugin(Map projects) { + for (project in projects) { + for (plugin in project.value.getPlugins()) { + if (plugin.class.name == "FlutterPlugin") { + return plugin; + } + } + def plugin = _findFlutterPlugin(project.value.childProjects); + if (plugin != null) { + return plugin; + } + } + return null; + } + + @Override + void apply(Project project) { + def plugin = findFlutterPlugin(project.rootProject); + + project.extensions.create("cargokit", CargoKitExtension) + + if (plugin == null) { + print("Flutter plugin not found, CargoKit plugin will not be applied.") + return; + } + + def cargoBuildDir = "${project.buildDir}/build" + + // Determine if the project is an application or library + def isApplication = plugin.project.plugins.hasPlugin('com.android.application') + def variants = isApplication ? plugin.project.android.applicationVariants : plugin.project.android.libraryVariants + + variants.all { variant -> + + final buildType = variant.buildType.name + + def cargoOutputDir = "${project.buildDir}/jniLibs/${buildType}"; + def jniLibs = project.android.sourceSets.maybeCreate(buildType).jniLibs; + jniLibs.srcDir(new File(cargoOutputDir)) + + def platforms = plugin.getTargetPlatforms().collect() + + // Same thing addFlutterDependencies does in flutter.gradle + if (buildType == "debug") { + platforms.add("android-x86") + platforms.add("android-x64") + } + + // The task name depends on plugin properties, which are not available + // at this point + project.getGradle().afterProject { + def taskName = "cargokitCargoBuild${project.cargokit.libname.capitalize()}${buildType.capitalize()}"; + + if (project.tasks.findByName(taskName)) { + return + } + + if (plugin.project.android.ndkVersion == null) { + throw new GradleException("Please set 'android.ndkVersion' in 'app/build.gradle'.") + } + + def task = project.tasks.create(taskName, CargoKitBuildTask.class) { + buildMode = variant.buildType.name + buildDir = cargoBuildDir + outputDir = cargoOutputDir + ndkVersion = plugin.project.android.ndkVersion + sdkDirectory = plugin.project.android.sdkDirectory + minSdkVersion = plugin.project.android.defaultConfig.minSdkVersion.apiLevel as int + compileSdkVersion = plugin.project.android.compileSdkVersion.substring(8) as int + targetPlatforms = platforms + pluginFile = CargoKitPlugin.file + } + def onTask = { newTask -> + if (newTask.name == "merge${buildType.capitalize()}NativeLibs") { + newTask.dependsOn task + // Fix gradle 7.4.2 not picking up JNI library changes + newTask.outputs.upToDateWhen { false } + } + } + project.tasks.each onTask + project.tasks.whenTaskAdded onTask + } + } + } +} diff --git a/bindings/dart-bip85/cargokit/run_build_tool.cmd b/bindings/dart-bip85/cargokit/run_build_tool.cmd new file mode 100755 index 0000000..c45d0aa --- /dev/null +++ b/bindings/dart-bip85/cargokit/run_build_tool.cmd @@ -0,0 +1,91 @@ +@echo off +setlocal + +setlocal ENABLEDELAYEDEXPANSION + +SET BASEDIR=%~dp0 + +if not exist "%CARGOKIT_TOOL_TEMP_DIR%" ( + mkdir "%CARGOKIT_TOOL_TEMP_DIR%" +) +cd /D "%CARGOKIT_TOOL_TEMP_DIR%" + +SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool +SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart + +set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/% + +( + echo name: build_tool_runner + echo version: 1.0.0 + echo publish_to: none + echo. + echo environment: + echo sdk: '^>=3.0.0 ^<4.0.0' + echo. + echo dependencies: + echo build_tool: + echo path: %BUILD_TOOL_PKG_DIR_POSIX% +) >pubspec.yaml + +if not exist bin ( + mkdir bin +) + +( + echo import 'package:build_tool/build_tool.dart' as build_tool; + echo void main^(List^ args^) ^{ + echo build_tool.runMain^(args^); + echo ^} +) >bin\build_tool_runner.dart + +SET PRECOMPILED=bin\build_tool_runner.dill + +REM To detect changes in package we compare output of DIR /s (recursive) +set PREV_PACKAGE_INFO=.dart_tool\package_info.prev +set CUR_PACKAGE_INFO=.dart_tool\package_info.cur + +DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig" + +REM Last line in dir output is free space on harddrive. That is bound to +REM change between invocation so we need to remove it +( + Set "Line=" + For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do ( + SetLocal EnableDelayedExpansion + If Defined Line Echo !Line! + EndLocal + Set "Line=%%A") +) >"%CUR_PACKAGE_INFO%" +DEL "%CUR_PACKAGE_INFO%_orig" + +REM Compare current directory listing with previous +FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1 + +If %ERRORLEVEL% neq 0 ( + REM Changed - copy current to previous and remove precompiled kernel + if exist "%PREV_PACKAGE_INFO%" ( + DEL "%PREV_PACKAGE_INFO%" + ) + MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" + if exist "%PRECOMPILED%" ( + DEL "%PRECOMPILED%" + ) +) + +REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO% +REM which means we need to do pub get and precompile +if not exist "%PRECOMPILED%" ( + echo Running pub get in "%cd%" + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart +) + +"%DART%" "%PRECOMPILED%" %* + +REM 253 means invalid snapshot version. +If %ERRORLEVEL% equ 253 ( + "%DART%" pub get --no-precompile + "%DART%" compile kernel bin/build_tool_runner.dart + "%DART%" "%PRECOMPILED%" %* +) diff --git a/bindings/dart-bip85/cargokit/run_build_tool.sh b/bindings/dart-bip85/cargokit/run_build_tool.sh new file mode 100755 index 0000000..6e594a2 --- /dev/null +++ b/bindings/dart-bip85/cargokit/run_build_tool.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +set -e + +BASEDIR=$(dirname "$0") + +mkdir -p "$CARGOKIT_TOOL_TEMP_DIR" + +cd "$CARGOKIT_TOOL_TEMP_DIR" + +# Write a very simple bin package in temp folder that depends on build_tool package +# from Cargokit. This is done to ensure that we don't pollute Cargokit folder +# with .dart_tool contents. + +BUILD_TOOL_PKG_DIR="$BASEDIR/build_tool" + +if [[ -z $FLUTTER_ROOT ]]; then # not defined + DART=dart +else + DART="$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart" +fi + +cat << EOF > "pubspec.yaml" +name: build_tool_runner +version: 1.0.0 +publish_to: none + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + build_tool: + path: "$BUILD_TOOL_PKG_DIR" +EOF + +mkdir -p "bin" + +cat << EOF > "bin/build_tool_runner.dart" +import 'package:build_tool/build_tool.dart' as build_tool; +void main(List args) { + build_tool.runMain(args); +} +EOF + +# Create alias for `shasum` if it does not exist and `sha1sum` exists +if ! [ -x "$(command -v shasum)" ] && [ -x "$(command -v sha1sum)" ]; then + shopt -s expand_aliases + alias shasum="sha1sum" +fi + +# Dart run will not cache any package that has a path dependency, which +# is the case for our build_tool_runner. So instead we precompile the package +# ourselves. +# To invalidate the cached kernel we use the hash of ls -LR of the build_tool +# package directory. This should be good enough, as the build_tool package +# itself is not meant to have any path dependencies. + +if [[ "$OSTYPE" == "darwin"* ]]; then + PACKAGE_HASH=$(ls -lTR "$BUILD_TOOL_PKG_DIR" | shasum) +else + PACKAGE_HASH=$(ls -lR --full-time "$BUILD_TOOL_PKG_DIR" | shasum) +fi + +PACKAGE_HASH_FILE=".package_hash" + +if [ -f "$PACKAGE_HASH_FILE" ]; then + EXISTING_HASH=$(cat "$PACKAGE_HASH_FILE") + if [ "$PACKAGE_HASH" != "$EXISTING_HASH" ]; then + rm "$PACKAGE_HASH_FILE" + fi +fi + +# Run pub get if needed. +if [ ! -f "$PACKAGE_HASH_FILE" ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + echo "$PACKAGE_HASH" > "$PACKAGE_HASH_FILE" +fi + +set +e + +"$DART" bin/build_tool_runner.dill "$@" + +exit_code=$? + +# 253 means invalid snapshot version. +if [ $exit_code == 253 ]; then + "$DART" pub get --no-precompile + "$DART" compile kernel bin/build_tool_runner.dart + "$DART" bin/build_tool_runner.dill "$@" + exit_code=$? +fi + +exit $exit_code diff --git a/bindings/dart-bip85/example/.gitignore b/bindings/dart-bip85/example/.gitignore new file mode 100644 index 0000000..79c113f --- /dev/null +++ b/bindings/dart-bip85/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/bindings/dart-bip85/example/.metadata b/bindings/dart-bip85/example/.metadata new file mode 100644 index 0000000..c2aa44b --- /dev/null +++ b/bindings/dart-bip85/example/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "603104015dd692ea3403755b55d07813d5cf8965" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: android + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: ios + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: linux + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: macos + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: web + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: windows + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/bindings/dart-bip85/example/README.md b/bindings/dart-bip85/example/README.md new file mode 100644 index 0000000..76be91f --- /dev/null +++ b/bindings/dart-bip85/example/README.md @@ -0,0 +1,11 @@ +# bip85_example + +Demonstrates how to use the bip85 plugin. + +entry point: `/lib/main.dart` +tests: `/integration_test/bip85_test.dart` + +Run integration tests: +```sh +flutter test integration_test/ +``` diff --git a/bindings/dart-bip85/example/analysis_options.yaml b/bindings/dart-bip85/example/analysis_options.yaml new file mode 100644 index 0000000..7e0f461 --- /dev/null +++ b/bindings/dart-bip85/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:lints/recommended.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/bindings/dart-bip85/example/android/.gitignore b/bindings/dart-bip85/example/android/.gitignore new file mode 100644 index 0000000..55afd91 --- /dev/null +++ b/bindings/dart-bip85/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/bindings/dart-bip85/example/android/app/build.gradle b/bindings/dart-bip85/example/android/app/build.gradle new file mode 100644 index 0000000..b0f69a8 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/build.gradle @@ -0,0 +1,44 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +android { + namespace = "com.example.bip85_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.bip85_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } +} + +flutter { + source = "../.." +} diff --git a/bindings/dart-bip85/example/android/app/src/debug/AndroidManifest.xml b/bindings/dart-bip85/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/bindings/dart-bip85/example/android/app/src/main/AndroidManifest.xml b/bindings/dart-bip85/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ce1cb38 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/bip85_example/MainActivity.kt b/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/bip85_example/MainActivity.kt new file mode 100644 index 0000000..4570d9b --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/bip85_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.bip85_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..70f8f08 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/bindings/dart-bip85/example/android/app/src/main/res/drawable-v21/launch_background.xml b/bindings/dart-bip85/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/bindings/dart-bip85/example/android/app/src/main/res/drawable/launch_background.xml b/bindings/dart-bip85/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/bindings/dart-bip85/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/bindings/dart-bip85/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/bindings/dart-bip85/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/bindings/dart-bip85/example/android/app/src/main/res/values-night/styles.xml b/bindings/dart-bip85/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/bindings/dart-bip85/example/android/app/src/main/res/values/styles.xml b/bindings/dart-bip85/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/bindings/dart-bip85/example/android/app/src/profile/AndroidManifest.xml b/bindings/dart-bip85/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/bindings/dart-bip85/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/bindings/dart-bip85/example/android/build.gradle b/bindings/dart-bip85/example/android/build.gradle new file mode 100644 index 0000000..d2ffbff --- /dev/null +++ b/bindings/dart-bip85/example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/bindings/dart-bip85/example/android/gradle.properties b/bindings/dart-bip85/example/android/gradle.properties new file mode 100644 index 0000000..2597170 --- /dev/null +++ b/bindings/dart-bip85/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/bindings/dart-bip85/example/android/gradle/wrapper/gradle-wrapper.properties b/bindings/dart-bip85/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..7bb2df6 --- /dev/null +++ b/bindings/dart-bip85/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/bindings/dart-bip85/example/android/settings.gradle b/bindings/dart-bip85/example/android/settings.gradle new file mode 100644 index 0000000..b9e43bd --- /dev/null +++ b/bindings/dart-bip85/example/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.1.0" apply false + id "org.jetbrains.kotlin.android" version "1.8.22" apply false +} + +include ":app" diff --git a/bindings/dart-bip85/example/integration_test/bip85_test.dart b/bindings/dart-bip85/example/integration_test/bip85_test.dart new file mode 100644 index 0000000..7977d6f --- /dev/null +++ b/bindings/dart-bip85/example/integration_test/bip85_test.dart @@ -0,0 +1,145 @@ +import 'package:bip85/bip85.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:bip85/bip85.dart' as bip85; +import 'package:integration_test/integration_test.dart'; + +void main() async { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + const xprv = + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"; + + setUpAll(() async => await bip85.LibBip85.init()); + + test('mnemonic', () { + final derived = bip85.toMnemonic(xprv: xprv, wordCount: 12, index: 0); + const expected = + "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose"; + + expect(derived, equals(expected.split(' '))); + }); + + group('mnemonic_in', () { + for (var language in Language.values) { + final name = language.label; + test(name, () { + final derived = bip85.toMnemonicIn( + xprv: xprv, language: name, wordCount: 12, index: 0); + + print(derived); + + expect( + derived, + equals(Mnemonic.fromWords(words: derived, language: language).words), + ); + }); + } + }); + + test('wif', () { + final derived = bip85.toWif(xprv: xprv, index: 0); + const expected = "Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp"; + + expect(derived, expected); + }); + + test('hex', () { + final derived = bip85.toHex(xprv: xprv, length: 64, index: 0); + const expected = + "492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c"; + + expect(derived, expected); + }); + + test('xpriv', () { + final derived = bip85.toXprv(xprv: xprv, index: 0); + const expected = + "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX"; + + expect(derived, expected); + }); + + test('toBase64', () { + final derived = bip85.toBase64(xprv: xprv, length: 21, index: 0); + const expected = "dKLoepugzdVJvdL56ogNV"; + expect(derived, expected); + }); + + test('toBase85', () { + final derived = bip85.toBase85(xprv: xprv, length: 12, index: 0); + const expected = "_s`{TW89)i4`"; + expect(derived, expected); + }); + + test('derive', () { + final derived = bip85.derive(xprv: xprv, path: "m/0'/0'"); + final expected = [ + 0xef, + 0xec, + 0xfb, + 0xcc, + 0xff, + 0xea, + 0x31, + 0x32, + 0x14, + 0x23, + 0x2d, + 0x29, + 0xe7, + 0x15, + 0x63, + 0xd9, + 0x41, + 0x22, + 0x9a, + 0xfb, + 0x43, + 0x38, + 0xc2, + 0x1f, + 0x95, + 0x17, + 0xc4, + 0x1a, + 0xaa, + 0x0d, + 0x16, + 0xf0, + 0x0b, + 0x83, + 0xd2, + 0xa0, + 0x9e, + 0xf7, + 0x47, + 0xe7, + 0xa6, + 0x4e, + 0x8e, + 0x2b, + 0xd5, + 0xa1, + 0x48, + 0x69, + 0xe6, + 0x93, + 0xda, + 0x66, + 0xce, + 0x94, + 0xac, + 0x2d, + 0xa5, + 0x70, + 0xab, + 0x7e, + 0xe4, + 0x86, + 0x18, + 0xf7 + ]; + + expect(derived, expected); + }); +} diff --git a/bindings/dart-bip85/example/ios/.gitignore b/bindings/dart-bip85/example/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/bindings/dart-bip85/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/bindings/dart-bip85/example/ios/Flutter/AppFrameworkInfo.plist b/bindings/dart-bip85/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/bindings/dart-bip85/example/ios/Flutter/Debug.xcconfig b/bindings/dart-bip85/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/bindings/dart-bip85/example/ios/Flutter/Release.xcconfig b/bindings/dart-bip85/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/bindings/dart-bip85/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/bindings/dart-bip85/example/ios/Podfile b/bindings/dart-bip85/example/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/bindings/dart-bip85/example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/bindings/dart-bip85/example/ios/Podfile.lock b/bindings/dart-bip85/example/ios/Podfile.lock new file mode 100644 index 0000000..22935e5 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - bip85 (0.0.1): + - Flutter + - Flutter (1.0.0) + - integration_test (0.0.1): + - Flutter + +DEPENDENCIES: + - bip85 (from `.symlinks/plugins/bip85/ios`) + - Flutter (from `Flutter`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + +EXTERNAL SOURCES: + bip85: + :path: ".symlinks/plugins/bip85/ios" + Flutter: + :path: Flutter + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + +SPEC CHECKSUMS: + bip85: 3059e217a3a606a100dd244f21d2fc61b0a1aa83 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.16.2 diff --git a/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.pbxproj b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..34b06fe --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,728 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 1933BBCE284DC506E614A7FE /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0C515202E7E1BA19C5B02B /* Pods_RunnerTests.framework */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 6F095C4E4C8776004464B32D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AF0D5762CDE36093EFDC09C /* Pods_Runner.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 2F5E754301B949F59A25A3B0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 366B68A60036A493C6D62CFD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 43C9840743FB05474A5E706E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 4AF0D5762CDE36093EFDC09C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 59DC335ED95FE48A6AE407F1 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8C0C515202E7E1BA19C5B02B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 930FD90423D84FF31997B252 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B2D8BD671C50A4A844C1FF7B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 704B898932CE4FF18B93FCA9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1933BBCE284DC506E614A7FE /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6F095C4E4C8776004464B32D /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13CB85E6FF7B7485885BF406 /* Pods */ = { + isa = PBXGroup; + children = ( + 2F5E754301B949F59A25A3B0 /* Pods-Runner.debug.xcconfig */, + 43C9840743FB05474A5E706E /* Pods-Runner.release.xcconfig */, + 366B68A60036A493C6D62CFD /* Pods-Runner.profile.xcconfig */, + B2D8BD671C50A4A844C1FF7B /* Pods-RunnerTests.debug.xcconfig */, + 930FD90423D84FF31997B252 /* Pods-RunnerTests.release.xcconfig */, + 59DC335ED95FE48A6AE407F1 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 20BA7A8985F3D2D1B01D38D4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4AF0D5762CDE36093EFDC09C /* Pods_Runner.framework */, + 8C0C515202E7E1BA19C5B02B /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 13CB85E6FF7B7485885BF406 /* Pods */, + 20BA7A8985F3D2D1B01D38D4 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 1E5893A183DB9D9BB01213CF /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 704B898932CE4FF18B93FCA9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 413C33B6C1BA0EBC9E14FB45 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 48A6ED68C221497C36D6885B /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1E5893A183DB9D9BB01213CF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 413C33B6C1BA0EBC9E14FB45 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 48A6ED68C221497C36D6885B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B2D8BD671C50A4A844C1FF7B /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 930FD90423D84FF31997B252 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 59DC335ED95FE48A6AE407F1 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/bindings/dart-bip85/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..15cada4 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/bindings/dart-bip85/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bindings/dart-bip85/example/ios/Runner/AppDelegate.swift b/bindings/dart-bip85/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/bindings/dart-bip85/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/bindings/dart-bip85/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/ios/Runner/Base.lproj/Main.storyboard b/bindings/dart-bip85/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/ios/Runner/Info.plist b/bindings/dart-bip85/example/ios/Runner/Info.plist new file mode 100644 index 0000000..330dcdc --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Bip85 + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + bip85_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/bindings/dart-bip85/example/ios/Runner/Runner-Bridging-Header.h b/bindings/dart-bip85/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/bindings/dart-bip85/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/bindings/dart-bip85/example/ios/RunnerTests/RunnerTests.swift b/bindings/dart-bip85/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/bindings/dart-bip85/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/bindings/dart-bip85/example/lib/main.dart b/bindings/dart-bip85/example/lib/main.dart new file mode 100644 index 0000000..1539840 --- /dev/null +++ b/bindings/dart-bip85/example/lib/main.dart @@ -0,0 +1,63 @@ +import 'package:bip85/bip85.dart'; +import 'package:flutter/material.dart'; +import 'package:bip85/bip85.dart' as bip85; +import 'package:collection/collection.dart'; + +Future main() async { + await bip85.LibBip85.init(); // mandatory + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + const xprv = + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"; + + const language = bip85.Language.english; + var derivedMnemonic = bip85.toMnemonicIn( + xprv: xprv, language: language.label, wordCount: 12, index: 0); + var expectedMnemonic = Mnemonic.fromSentence( + "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose", + language); + assert(ListEquality().equals(derivedMnemonic, expectedMnemonic.words)); + + var derived = bip85.toWif(xprv: xprv, index: 0); + var expected = "Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp"; + assert(derived == expected); + + derived = bip85.toHex(xprv: xprv, length: 64, index: 0); + expected = + "492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c"; + assert(derived == expected); + + derived = bip85.toXprv(xprv: xprv, index: 0); + expected = + "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX"; + assert(derived == expected); + + derived = bip85.toBase64(xprv: xprv, length: 21, index: 0); + expected = "dKLoepugzdVJvdL56ogNV"; + assert(derived == expected); + + derived = bip85.toBase85(xprv: xprv, length: 12, index: 0); + expected = "_s`{TW89)i4`"; + assert(derived == expected); + + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('flutter_rust_bridge bip85')), + body: Center( + child: Text( + Mnemonic.fromWords( + words: bip85.toMnemonic(xprv: xprv, wordCount: 12, index: 0), + language: language, + ).sentence, + ), + ), + ), + ); + } +} diff --git a/bindings/dart-bip85/example/linux/.gitignore b/bindings/dart-bip85/example/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/bindings/dart-bip85/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/bindings/dart-bip85/example/linux/CMakeLists.txt b/bindings/dart-bip85/example/linux/CMakeLists.txt new file mode 100644 index 0000000..0dc763b --- /dev/null +++ b/bindings/dart-bip85/example/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# 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 "bip85_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.bip85") + +# 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. +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() + +# 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() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +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. +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. +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" +) + + +# 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) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +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) + +# 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/bindings/dart-bip85/example/linux/flutter/CMakeLists.txt b/bindings/dart-bip85/example/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/bindings/dart-bip85/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.cc b/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..e71a16d --- /dev/null +++ b/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.h b/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/bindings/dart-bip85/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bindings/dart-bip85/example/linux/flutter/generated_plugins.cmake b/bindings/dart-bip85/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..572e830 --- /dev/null +++ b/bindings/dart-bip85/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + bip85 +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/bindings/dart-bip85/example/linux/main.cc b/bindings/dart-bip85/example/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/bindings/dart-bip85/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/bindings/dart-bip85/example/linux/my_application.cc b/bindings/dart-bip85/example/linux/my_application.cc new file mode 100644 index 0000000..6b31953 --- /dev/null +++ b/bindings/dart-bip85/example/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "bip85_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "bip85_example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/bindings/dart-bip85/example/linux/my_application.h b/bindings/dart-bip85/example/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/bindings/dart-bip85/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/bindings/dart-bip85/example/macos/.gitignore b/bindings/dart-bip85/example/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/bindings/dart-bip85/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/bindings/dart-bip85/example/macos/Flutter/Flutter-Debug.xcconfig b/bindings/dart-bip85/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/bindings/dart-bip85/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bindings/dart-bip85/example/macos/Flutter/Flutter-Release.xcconfig b/bindings/dart-bip85/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bindings/dart-bip85/example/macos/Flutter/GeneratedPluginRegistrant.swift b/bindings/dart-bip85/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..cccf817 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/bindings/dart-bip85/example/macos/Podfile b/bindings/dart-bip85/example/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/bindings/dart-bip85/example/macos/Podfile.lock b/bindings/dart-bip85/example/macos/Podfile.lock new file mode 100644 index 0000000..9d5c6ea --- /dev/null +++ b/bindings/dart-bip85/example/macos/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - bip85 (0.0.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + +DEPENDENCIES: + - bip85 (from `Flutter/ephemeral/.symlinks/plugins/bip85/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + +EXTERNAL SOURCES: + bip85: + :path: Flutter/ephemeral/.symlinks/plugins/bip85/macos + FlutterMacOS: + :path: Flutter/ephemeral + +SPEC CHECKSUMS: + bip85: e3585c4c33a506a14c19d4d2165160be6c22fecb + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.16.2 diff --git a/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.pbxproj b/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ea647a4 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 45B43586F58AC1162D25CCE2 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B32FB13DB1E6E120B6903A37 /* Pods_RunnerTests.framework */; }; + D69BFA5DA5FC657AD7674709 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB40E8F957511B04F5D4B239 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1B122682F1E292BC93BA4275 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 20D7D7AB646E49A3A225178D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* bip85_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bip85_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 647F423E862258B119B1485C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + AC7E172BECD9C6D3CEEF01AF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + B32FB13DB1E6E120B6903A37 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D05A397473DD79713A9D0A71 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + F84DC8CE367F5D290452EA01 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + FB40E8F957511B04F5D4B239 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 45B43586F58AC1162D25CCE2 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D69BFA5DA5FC657AD7674709 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 10A4B067238B12C7D7174C33 /* Pods */ = { + isa = PBXGroup; + children = ( + F84DC8CE367F5D290452EA01 /* Pods-Runner.debug.xcconfig */, + 647F423E862258B119B1485C /* Pods-Runner.release.xcconfig */, + 20D7D7AB646E49A3A225178D /* Pods-Runner.profile.xcconfig */, + 1B122682F1E292BC93BA4275 /* Pods-RunnerTests.debug.xcconfig */, + AC7E172BECD9C6D3CEEF01AF /* Pods-RunnerTests.release.xcconfig */, + D05A397473DD79713A9D0A71 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 10A4B067238B12C7D7174C33 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* bip85_example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + FB40E8F957511B04F5D4B239 /* Pods_Runner.framework */, + B32FB13DB1E6E120B6903A37 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 9E92FCBECAD59C33FD4F88C0 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 519E010801580DFD6607CEB0 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 6D2DE88D8675848410A0D159 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* bip85_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 519E010801580DFD6607CEB0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 6D2DE88D8675848410A0D159 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9E92FCBECAD59C33FD4F88C0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1B122682F1E292BC93BA4275 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bip85_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bip85_example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AC7E172BECD9C6D3CEEF01AF /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bip85_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bip85_example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D05A397473DD79713A9D0A71 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bip85_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bip85_example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bindings/dart-bip85/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/bindings/dart-bip85/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..b418a20 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/bindings/dart-bip85/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/bindings/dart-bip85/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bindings/dart-bip85/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bindings/dart-bip85/example/macos/Runner/AppDelegate.swift b/bindings/dart-bip85/example/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..b3c1761 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/bindings/dart-bip85/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/bindings/dart-bip85/example/macos/Runner/Base.lproj/MainMenu.xib b/bindings/dart-bip85/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/dart-bip85/example/macos/Runner/Configs/AppInfo.xcconfig b/bindings/dart-bip85/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..7875223 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = bip85_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.bip85Example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/bindings/dart-bip85/example/macos/Runner/Configs/Debug.xcconfig b/bindings/dart-bip85/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/bindings/dart-bip85/example/macos/Runner/Configs/Release.xcconfig b/bindings/dart-bip85/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/bindings/dart-bip85/example/macos/Runner/Configs/Warnings.xcconfig b/bindings/dart-bip85/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/bindings/dart-bip85/example/macos/Runner/DebugProfile.entitlements b/bindings/dart-bip85/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/bindings/dart-bip85/example/macos/Runner/Info.plist b/bindings/dart-bip85/example/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/bindings/dart-bip85/example/macos/Runner/MainFlutterWindow.swift b/bindings/dart-bip85/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/bindings/dart-bip85/example/macos/Runner/Release.entitlements b/bindings/dart-bip85/example/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/bindings/dart-bip85/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/bindings/dart-bip85/example/macos/RunnerTests/RunnerTests.swift b/bindings/dart-bip85/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/bindings/dart-bip85/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/bindings/dart-bip85/example/pubspec.lock b/bindings/dart-bip85/example/pubspec.lock new file mode 100644 index 0000000..58d7268 --- /dev/null +++ b/bindings/dart-bip85/example/pubspec.lock @@ -0,0 +1,355 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" + async: + dependency: transitive + description: + name: async + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + url: "https://pub.dev" + source: hosted + version: "2.12.0" + bip39_mnemonic: + dependency: transitive + description: + name: bip39_mnemonic + sha256: dd6bdfc2547d986b2c00f99bba209c69c0b6fa5c1a185e1f728998282f1249d5 + url: "https://pub.dev" + source: hosted + version: "4.0.1" + bip85: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "2.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + url: "https://pub.dev" + source: hosted + version: "1.3.2" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_rust_bridge: + dependency: transitive + description: + name: flutter_rust_bridge + sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611" + url: "https://pub.dev" + source: hosted + version: "2.9.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + url: "https://pub.dev" + source: hosted + version: "10.0.8" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + process: + dependency: transitive + description: + name: process + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + url: "https://pub.dev" + source: hosted + version: "5.0.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + unorm_dart: + dependency: transitive + description: + name: unorm_dart + sha256: "8e3870a1caa60bde8352f9597dd3535d8068613269444f8e35ea8925ec84c1f5" + url: "https://pub.dev" + source: hosted + version: "0.3.1+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + url: "https://pub.dev" + source: hosted + version: "14.3.1" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + url: "https://pub.dev" + source: hosted + version: "3.0.4" +sdks: + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/bindings/dart-bip85/example/pubspec.yaml b/bindings/dart-bip85/example/pubspec.yaml new file mode 100644 index 0000000..2e22da7 --- /dev/null +++ b/bindings/dart-bip85/example/pubspec.yaml @@ -0,0 +1,106 @@ +name: bip85_example +description: "Demonstrates how to use the bip85 plugin." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.5.4 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + bip85: + # # When depending on this package from a real application you should use: + # # bip85: ^x.y.z + # # See https://dart.dev/tools/pub/dependencies#version-constraints + # # The example app is bundled with the plugin so we use a path dependency on + # # the parent directory to use the current plugin's version. + path: ../ + # bip85: + # git: + # url: https://github.com/ethicnology/rust-bip85.git + # path: bindings/dart-bip85 + # ref: master + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.8 + collection: ^1.19.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + lints: ^5.0.0 + integration_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/bindings/dart-bip85/example/windows/.gitignore b/bindings/dart-bip85/example/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/bindings/dart-bip85/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/bindings/dart-bip85/example/windows/CMakeLists.txt b/bindings/dart-bip85/example/windows/CMakeLists.txt new file mode 100644 index 0000000..4c6c1a0 --- /dev/null +++ b/bindings/dart-bip85/example/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(bip85_example 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 "bip85_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + 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() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# 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_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +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) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +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) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/bindings/dart-bip85/example/windows/flutter/CMakeLists.txt b/bindings/dart-bip85/example/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/bindings/dart-bip85/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.cc b/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..8b6d468 --- /dev/null +++ b/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.h b/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/bindings/dart-bip85/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bindings/dart-bip85/example/windows/flutter/generated_plugins.cmake b/bindings/dart-bip85/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..7bbc6ae --- /dev/null +++ b/bindings/dart-bip85/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + bip85 +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/bindings/dart-bip85/example/windows/runner/CMakeLists.txt b/bindings/dart-bip85/example/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, 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. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/bindings/dart-bip85/example/windows/runner/Runner.rc b/bindings/dart-bip85/example/windows/runner/Runner.rc new file mode 100644 index 0000000..82facc4 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "bip85_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "bip85_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "bip85_example.exe" "\0" + VALUE "ProductName", "bip85_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/bindings/dart-bip85/example/windows/runner/flutter_window.cpp b/bindings/dart-bip85/example/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/bindings/dart-bip85/example/windows/runner/flutter_window.h b/bindings/dart-bip85/example/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/bindings/dart-bip85/example/windows/runner/main.cpp b/bindings/dart-bip85/example/windows/runner/main.cpp new file mode 100644 index 0000000..3ba064e --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"bip85_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/bindings/dart-bip85/example/windows/runner/resource.h b/bindings/dart-bip85/example/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/bindings/dart-bip85/example/windows/runner/resources/app_icon.ico b/bindings/dart-bip85/example/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..c04e20c Binary files /dev/null and b/bindings/dart-bip85/example/windows/runner/resources/app_icon.ico differ diff --git a/bindings/dart-bip85/example/windows/runner/runner.exe.manifest b/bindings/dart-bip85/example/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/bindings/dart-bip85/example/windows/runner/utils.cpp b/bindings/dart-bip85/example/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/bindings/dart-bip85/example/windows/runner/utils.h b/bindings/dart-bip85/example/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/bindings/dart-bip85/example/windows/runner/win32_window.cpp b/bindings/dart-bip85/example/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/bindings/dart-bip85/example/windows/runner/win32_window.h b/bindings/dart-bip85/example/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/bindings/dart-bip85/example/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/bindings/dart-bip85/flutter_rust_bridge.yaml b/bindings/dart-bip85/flutter_rust_bridge.yaml new file mode 100644 index 0000000..0ffc1b1 --- /dev/null +++ b/bindings/dart-bip85/flutter_rust_bridge.yaml @@ -0,0 +1,4 @@ +rust_input: crate::api +rust_root: rust/ +dart_output: lib/src/rust +dart_entrypoint_class_name: LibBip85 diff --git a/bindings/dart-bip85/ios/Classes/dummy_file.c b/bindings/dart-bip85/ios/Classes/dummy_file.c new file mode 100644 index 0000000..e06dab9 --- /dev/null +++ b/bindings/dart-bip85/ios/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/bindings/dart-bip85/ios/bip85.podspec b/bindings/dart-bip85/ios/bip85.podspec new file mode 100644 index 0000000..59ac5b8 --- /dev/null +++ b/bindings/dart-bip85/ios/bip85.podspec @@ -0,0 +1,45 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint bip85.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'bip85' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '11.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../rust bip85', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/libbip85.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libbip85.a', + } +end \ No newline at end of file diff --git a/bindings/dart-bip85/lib/bip85.dart b/bindings/dart-bip85/lib/bip85.dart new file mode 100644 index 0000000..c9a3827 --- /dev/null +++ b/bindings/dart-bip85/lib/bip85.dart @@ -0,0 +1,5 @@ +library; + +export 'src/rust/api/bip85.dart'; +export 'src/rust/frb_generated.dart' show LibBip85; +export 'package:bip39_mnemonic/bip39_mnemonic.dart'; diff --git a/bindings/dart-bip85/lib/src/rust/api/bip85.dart b/bindings/dart-bip85/lib/src/rust/api/bip85.dart new file mode 100644 index 0000000..5dff05b --- /dev/null +++ b/bindings/dart-bip85/lib/src/rust/api/bip85.dart @@ -0,0 +1,43 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.9.0. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +Uint8List derive({required String xprv, required String path}) => + LibBip85.instance.api.crateApiBip85Derive(xprv: xprv, path: path); + +String toWif({required String xprv, required int index}) => + LibBip85.instance.api.crateApiBip85ToWif(xprv: xprv, index: index); + +String toXprv({required String xprv, required int index}) => + LibBip85.instance.api.crateApiBip85ToXprv(xprv: xprv, index: index); + +String toHex({required String xprv, required int length, required int index}) => + LibBip85.instance.api + .crateApiBip85ToHex(xprv: xprv, length: length, index: index); + +List toMnemonic( + {required String xprv, required int wordCount, required int index}) => + LibBip85.instance.api.crateApiBip85ToMnemonic( + xprv: xprv, wordCount: wordCount, index: index); + +List toMnemonicIn( + {required String xprv, + required String language, + required int wordCount, + required int index}) => + LibBip85.instance.api.crateApiBip85ToMnemonicIn( + xprv: xprv, language: language, wordCount: wordCount, index: index); + +String toBase64( + {required String xprv, required int length, required int index}) => + LibBip85.instance.api + .crateApiBip85ToBase64(xprv: xprv, length: length, index: index); + +String toBase85( + {required String xprv, required int length, required int index}) => + LibBip85.instance.api + .crateApiBip85ToBase85(xprv: xprv, length: length, index: index); diff --git a/bindings/dart-bip85/lib/src/rust/frb_generated.dart b/bindings/dart-bip85/lib/src/rust/frb_generated.dart new file mode 100644 index 0000000..a077e4d --- /dev/null +++ b/bindings/dart-bip85/lib/src/rust/frb_generated.dart @@ -0,0 +1,462 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.9.0. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'api/bip85.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'frb_generated.dart'; +import 'frb_generated.io.dart' + if (dart.library.js_interop) 'frb_generated.web.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +/// Main entrypoint of the Rust API +class LibBip85 + extends BaseEntrypoint { + @internal + static final instance = LibBip85._(); + + LibBip85._(); + + /// Initialize flutter_rust_bridge + static Future init({ + LibBip85Api? api, + BaseHandler? handler, + ExternalLibrary? externalLibrary, + }) async { + await instance.initImpl( + api: api, + handler: handler, + externalLibrary: externalLibrary, + ); + } + + /// Initialize flutter_rust_bridge in mock mode. + /// No libraries for FFI are loaded. + static void initMock({ + required LibBip85Api api, + }) { + instance.initMockImpl( + api: api, + ); + } + + /// Dispose flutter_rust_bridge + /// + /// The call to this function is optional, since flutter_rust_bridge (and everything else) + /// is automatically disposed when the app stops. + static void dispose() => instance.disposeImpl(); + + @override + ApiImplConstructor get apiImplConstructor => + LibBip85ApiImpl.new; + + @override + WireConstructor get wireConstructor => + LibBip85Wire.fromExternalLibrary; + + @override + Future executeRustInitializers() async {} + + @override + ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig => + kDefaultExternalLibraryLoaderConfig; + + @override + String get codegenVersion => '2.9.0'; + + @override + int get rustContentHash => 457669416; + + static const kDefaultExternalLibraryLoaderConfig = + ExternalLibraryLoaderConfig( + stem: 'bip85', + ioDirectory: 'rust/target/release/', + webPrefix: 'pkg/', + ); +} + +abstract class LibBip85Api extends BaseApi { + Uint8List crateApiBip85Derive({required String xprv, required String path}); + + String crateApiBip85ToBase64( + {required String xprv, required int length, required int index}); + + String crateApiBip85ToBase85( + {required String xprv, required int length, required int index}); + + String crateApiBip85ToHex( + {required String xprv, required int length, required int index}); + + List crateApiBip85ToMnemonic( + {required String xprv, required int wordCount, required int index}); + + List crateApiBip85ToMnemonicIn( + {required String xprv, + required String language, + required int wordCount, + required int index}); + + String crateApiBip85ToWif({required String xprv, required int index}); + + String crateApiBip85ToXprv({required String xprv, required int index}); +} + +class LibBip85ApiImpl extends LibBip85ApiImplPlatform implements LibBip85Api { + LibBip85ApiImpl({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @override + Uint8List crateApiBip85Derive({required String xprv, required String path}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_String(path, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 1)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_prim_u_8_strict, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85DeriveConstMeta, + argValues: [xprv, path], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85DeriveConstMeta => const TaskConstMeta( + debugName: "derive", + argNames: ["xprv", "path"], + ); + + @override + String crateApiBip85ToBase64( + {required String xprv, required int length, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(length, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 2)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToBase64ConstMeta, + argValues: [xprv, length, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToBase64ConstMeta => const TaskConstMeta( + debugName: "to_base64", + argNames: ["xprv", "length", "index"], + ); + + @override + String crateApiBip85ToBase85( + {required String xprv, required int length, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(length, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 3)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToBase85ConstMeta, + argValues: [xprv, length, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToBase85ConstMeta => const TaskConstMeta( + debugName: "to_base85", + argNames: ["xprv", "length", "index"], + ); + + @override + String crateApiBip85ToHex( + {required String xprv, required int length, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(length, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 4)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToHexConstMeta, + argValues: [xprv, length, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToHexConstMeta => const TaskConstMeta( + debugName: "to_hex", + argNames: ["xprv", "length", "index"], + ); + + @override + List crateApiBip85ToMnemonic( + {required String xprv, required int wordCount, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(wordCount, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 5)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToMnemonicConstMeta, + argValues: [xprv, wordCount, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToMnemonicConstMeta => const TaskConstMeta( + debugName: "to_mnemonic", + argNames: ["xprv", "wordCount", "index"], + ); + + @override + List crateApiBip85ToMnemonicIn( + {required String xprv, + required String language, + required int wordCount, + required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_String(language, serializer); + sse_encode_u_32(wordCount, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 6)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToMnemonicInConstMeta, + argValues: [xprv, language, wordCount, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToMnemonicInConstMeta => const TaskConstMeta( + debugName: "to_mnemonic_in", + argNames: ["xprv", "language", "wordCount", "index"], + ); + + @override + String crateApiBip85ToWif({required String xprv, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 7)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToWifConstMeta, + argValues: [xprv, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToWifConstMeta => const TaskConstMeta( + debugName: "to_wif", + argNames: ["xprv", "index"], + ); + + @override + String crateApiBip85ToXprv({required String xprv, required int index}) { + return handler.executeSync(SyncTask( + callFfi: () { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(xprv, serializer); + sse_encode_u_32(index, serializer); + return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 8)!; + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiBip85ToXprvConstMeta, + argValues: [xprv, index], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiBip85ToXprvConstMeta => const TaskConstMeta( + debugName: "to_xprv", + argNames: ["xprv", "index"], + ); + + @protected + String dco_decode_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as String; + } + + @protected + List dco_decode_list_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_String).toList(); + } + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as Uint8List; + } + + @protected + int dco_decode_u_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + int dco_decode_u_8(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + void dco_decode_unit(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return; + } + + @protected + String sse_decode_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var inner = sse_decode_list_prim_u_8_strict(deserializer); + return utf8.decoder.convert(inner); + } + + @protected + List sse_decode_list_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_String(deserializer)); + } + return ans_; + } + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint8List(len_); + } + + @protected + int sse_decode_u_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint32(); + } + + @protected + int sse_decode_u_8(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8(); + } + + @protected + void sse_decode_unit(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + int sse_decode_i_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getInt32(); + } + + @protected + bool sse_decode_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8() != 0; + } + + @protected + void sse_encode_String(String self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); + } + + @protected + void sse_encode_list_String(List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_String(item, serializer); + } + } + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint8List(self); + } + + @protected + void sse_encode_u_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint32(self); + } + + @protected + void sse_encode_u_8(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self); + } + + @protected + void sse_encode_unit(void self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + void sse_encode_i_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putInt32(self); + } + + @protected + void sse_encode_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self ? 1 : 0); + } +} diff --git a/bindings/dart-bip85/lib/src/rust/frb_generated.io.dart b/bindings/dart-bip85/lib/src/rust/frb_generated.io.dart new file mode 100644 index 0000000..a33b631 --- /dev/null +++ b/bindings/dart-bip85/lib/src/rust/frb_generated.io.dart @@ -0,0 +1,102 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.9.0. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'api/bip85.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; +import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; + +abstract class LibBip85ApiImplPlatform extends BaseApiImpl { + LibBip85ApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + String dco_decode_String(dynamic raw); + + @protected + List dco_decode_list_String(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + int dco_decode_u_32(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + List sse_decode_list_String(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_list_String(List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, SseSerializer serializer); + + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); +} + +// Section: wire_class + +class LibBip85Wire implements BaseWire { + factory LibBip85Wire.fromExternalLibrary(ExternalLibrary lib) => + LibBip85Wire(lib.ffiDynamicLibrary); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + LibBip85Wire(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; +} diff --git a/bindings/dart-bip85/lib/src/rust/frb_generated.web.dart b/bindings/dart-bip85/lib/src/rust/frb_generated.web.dart new file mode 100644 index 0000000..73566a7 --- /dev/null +++ b/bindings/dart-bip85/lib/src/rust/frb_generated.web.dart @@ -0,0 +1,102 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.9.0. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +// Static analysis wrongly picks the IO variant, thus ignore this +// ignore_for_file: argument_type_not_assignable + +import 'api/bip85.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; + +abstract class LibBip85ApiImplPlatform extends BaseApiImpl { + LibBip85ApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + String dco_decode_String(dynamic raw); + + @protected + List dco_decode_list_String(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + int dco_decode_u_32(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + List sse_decode_list_String(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_list_String(List self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, SseSerializer serializer); + + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); +} + +// Section: wire_class + +class LibBip85Wire implements BaseWire { + LibBip85Wire.fromExternalLibrary(ExternalLibrary lib); +} + +@JS('wasm_bindgen') +external LibBip85WasmModule get wasmModule; + +@JS() +@anonymous +extension type LibBip85WasmModule._(JSObject _) implements JSObject {} diff --git a/bindings/dart-bip85/linux/CMakeLists.txt b/bindings/dart-bip85/linux/CMakeLists.txt new file mode 100644 index 0000000..5cdc58b --- /dev/null +++ b/bindings/dart-bip85/linux/CMakeLists.txt @@ -0,0 +1,19 @@ +# 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. +cmake_minimum_required(VERSION 3.10) + +# Project-level configuration. +set(PROJECT_NAME "bip85") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../rust bip85 "") + +# 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(bip85_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/bindings/dart-bip85/macos/Classes/dummy_file.c b/bindings/dart-bip85/macos/Classes/dummy_file.c new file mode 100644 index 0000000..e06dab9 --- /dev/null +++ b/bindings/dart-bip85/macos/Classes/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to force CocoaPods to create a framework. diff --git a/bindings/dart-bip85/macos/bip85.podspec b/bindings/dart-bip85/macos/bip85.podspec new file mode 100644 index 0000000..ad0496c --- /dev/null +++ b/bindings/dart-bip85/macos/bip85.podspec @@ -0,0 +1,44 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint bip85.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'bip85' + s.version = '0.0.1' + s.summary = 'A new Flutter FFI plugin project.' + s.description = <<-DESC +A new Flutter FFI plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' + + s.script_phase = { + :name => 'Build Rust library', + # First argument is relative path to the `rust` folder, second is name of rust library + :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../rust bip85', + :execution_position => :before_compile, + :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], + # Let XCode know that the static library referenced in -force_load below is + # created by this build step. + :output_files => ["${BUILT_PRODUCTS_DIR}/libbip85.a"], + } + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # Flutter.framework does not contain a i386 slice. + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libbip85.a', + } +end \ No newline at end of file diff --git a/bindings/dart-bip85/pubspec.yaml b/bindings/dart-bip85/pubspec.yaml new file mode 100644 index 0000000..52285cf --- /dev/null +++ b/bindings/dart-bip85/pubspec.yaml @@ -0,0 +1,86 @@ +name: bip85 +description: "Bindings for the rust library bip85_extended. We recommend you to use the package bip85_entropy instead of this package." +version: 3.0.0 +homepage: https://github.com/ethicnology/rust-bip85/tree/master/bindings/dart-bip85 +repository: https://github.com/ethicnology/rust-bip85 + +environment: + sdk: ^3.5.4 + flutter: '>=3.3.0' + +dependencies: + bip39_mnemonic: ^4.0.1 + ffi: ^2.1.3 + flutter: + sdk: flutter + flutter_rust_bridge: ">2.8.0 <=2.9.0" + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + ffigen: ^18.1.0 + flutter_test: + sdk: flutter + lints: ^5.0.0 + integration_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + android: + ffiPlugin: true + ios: + ffiPlugin: true + linux: + ffiPlugin: true + macos: + ffiPlugin: true + windows: + ffiPlugin: true + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/to/asset-from-package + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/to/font-from-package diff --git a/bindings/dart-bip85/rust/.gitignore b/bindings/dart-bip85/rust/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/bindings/dart-bip85/rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/bindings/dart-bip85/rust/Cargo.toml b/bindings/dart-bip85/rust/Cargo.toml new file mode 100644 index 0000000..6533e3b --- /dev/null +++ b/bindings/dart-bip85/rust/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "bip85" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +bip85_extended = { path = "../../..", features = ["all-languages"] } +flutter_rust_bridge = "=2.9.0" +hex = "0.4.3" diff --git a/bindings/dart-bip85/rust/cargokit.yaml b/bindings/dart-bip85/rust/cargokit.yaml new file mode 100644 index 0000000..d933bd4 --- /dev/null +++ b/bindings/dart-bip85/rust/cargokit.yaml @@ -0,0 +1,15 @@ +cargo: + debug: # Configuration of cargo execution during debug builds + toolchain: stable # default + release: # Configuration of cargo execution for release builds + toolchain: nightly # rustup will be invoked with nightly toolchain + extra_flags: # extra arguments passed to cargo build + - -Z + - build-std=panic_abort,std + +precompiled_binaries: + # Uri prefix used when downloading precompiled binaries. + url_prefix: https://github.com/ethicnology/rust-bip85/releases/download/precompiled_ + + # Public key for verifying downloaded precompiled binaries. + public_key: e56a85ab8294c9f0cd8bb58a624e23b83b5682380d048e41b041b6624d949976 \ No newline at end of file diff --git a/bindings/dart-bip85/rust/src/api/bip85.rs b/bindings/dart-bip85/rust/src/api/bip85.rs new file mode 100644 index 0000000..6477cd4 --- /dev/null +++ b/bindings/dart-bip85/rust/src/api/bip85.rs @@ -0,0 +1,77 @@ +use std::str::FromStr; + +use bip85_extended::bip39::Language; +use bip85_extended::bitcoin::bip32::{DerivationPath, Xpriv}; +use bip85_extended::bitcoin::secp256k1::Secp256k1; + +#[flutter_rust_bridge::frb(sync)] +pub fn derive(xprv: String, path: String) -> Vec { + let root = Xpriv::from_str(&xprv).unwrap(); + let derivation_path = DerivationPath::from_str(&path).unwrap(); + let derived = bip85_extended::derive(&Secp256k1::new(), &root, &derivation_path).unwrap(); + return derived; +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_wif(xprv: String, index: u32) -> String { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_wif(&Secp256k1::new(), &root, index).unwrap(); + return derived.to_string(); +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_xprv(xprv: String, index: u32) -> String { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_xprv(&Secp256k1::new(), &root, index).unwrap(); + return derived.to_string(); +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_hex(xprv: String, length: u32, index: u32) -> String { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_hex(&Secp256k1::new(), &root, length, index).unwrap(); + return derived; +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_mnemonic(xprv: String, word_count: u32, index: u32) -> Vec { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_mnemonic(&Secp256k1::new(), &root, word_count, index).unwrap(); + return derived.words().map(|s| s.to_string()).collect(); +} + + +#[flutter_rust_bridge::frb(sync)] +pub fn to_mnemonic_in(xprv: String, language: String, word_count: u32, index: u32, ) -> Vec { + let language = match language.to_lowercase().as_str() { + "english" => Language::English, + "japanese" => Language::Japanese, + "korean" => Language::Korean, + "spanish" => Language::Spanish, + "chinese-simplified" => Language::SimplifiedChinese, + "chinese-traditional" => Language::TraditionalChinese, + "french" => Language::French, + "italian" => Language::Italian, + "czech" => Language::Czech, + "portuguese" => Language::Portuguese, + _ => Language::English, + }; + + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_mnemonic_in(&Secp256k1::new(), &root, language, word_count, index).unwrap(); + return derived.words().map(|s| s.to_string()).collect(); +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_base64(xprv: String, length: u32, index: u32) -> String { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_pwd_base64(&Secp256k1::new(), &root, length, index).unwrap(); + return derived.to_string(); +} + +#[flutter_rust_bridge::frb(sync)] +pub fn to_base85(xprv: String, length: u32, index: u32) -> String { + let root = Xpriv::from_str(&xprv).unwrap(); + let derived = bip85_extended::to_pwd_base85(&Secp256k1::new(), &root, length, index).unwrap(); + return derived.to_string(); +} \ No newline at end of file diff --git a/bindings/dart-bip85/rust/src/api/mod.rs b/bindings/dart-bip85/rust/src/api/mod.rs new file mode 100644 index 0000000..d9122d1 --- /dev/null +++ b/bindings/dart-bip85/rust/src/api/mod.rs @@ -0,0 +1 @@ +pub mod bip85; diff --git a/bindings/dart-bip85/rust/src/frb_generated.io.rs b/bindings/dart-bip85/rust/src/frb_generated.io.rs new file mode 100644 index 0000000..44a9b90 --- /dev/null +++ b/bindings/dart-bip85/rust/src/frb_generated.io.rs @@ -0,0 +1,13 @@ +// This file is automatically generated, so please do not edit it. +// Generated by `flutter_rust_bridge`@ 2.0.0. + +// Section: imports + +use super::*; +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate_io!(); diff --git a/bindings/dart-bip85/rust/src/frb_generated.rs b/bindings/dart-bip85/rust/src/frb_generated.rs new file mode 100644 index 0000000..a70d7b7 --- /dev/null +++ b/bindings/dart-bip85/rust/src/frb_generated.rs @@ -0,0 +1,525 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.9.0. + +#![allow( + non_camel_case_types, + unused, + non_snake_case, + clippy::needless_return, + clippy::redundant_closure_call, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::unused_unit, + clippy::double_parens, + clippy::let_and_return, + clippy::too_many_arguments, + clippy::match_single_binding, + clippy::clone_on_copy, + clippy::let_unit_value, + clippy::deref_addrof, + clippy::explicit_auto_deref, + clippy::borrow_deref_ref, + clippy::needless_borrow +)] + +// Section: imports + +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate!( + default_stream_sink_codec = SseCodec, + default_rust_opaque = RustOpaqueMoi, + default_rust_auto_opaque = RustAutoOpaqueMoi, +); +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.9.0"; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 457669416; + +// Section: executor + +flutter_rust_bridge::frb_generated_default_handler!(); + +// Section: wire_funcs + +fn wire__crate__api__bip85__derive_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "derive", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_path = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::derive(api_xprv, api_path))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_base64_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_base64", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_length = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::to_base64( + api_xprv, api_length, api_index, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_base85_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_base85", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_length = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::to_base85( + api_xprv, api_length, api_index, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_hex_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_hex", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_length = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::to_hex( + api_xprv, api_length, api_index, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_mnemonic_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_mnemonic", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_word_count = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::to_mnemonic( + api_xprv, + api_word_count, + api_index, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_mnemonic_in_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_mnemonic_in", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_language = ::sse_decode(&mut deserializer); + let api_word_count = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::bip85::to_mnemonic_in( + api_xprv, + api_language, + api_word_count, + api_index, + ))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_wif_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_wif", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = + Result::<_, ()>::Ok(crate::api::bip85::to_wif(api_xprv, api_index))?; + Ok(output_ok) + })()) + }, + ) +} +fn wire__crate__api__bip85__to_xprv_impl( + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "to_xprv", + port: None, + mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_xprv = ::sse_decode(&mut deserializer); + let api_index = ::sse_decode(&mut deserializer); + deserializer.end(); + transform_result_sse::<_, ()>((move || { + let output_ok = + Result::<_, ()>::Ok(crate::api::bip85::to_xprv(api_xprv, api_index))?; + Ok(output_ok) + })()) + }, + ) +} + +// Section: dart2rust + +impl SseDecode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return String::from_utf8(inner).unwrap(); + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u32::().unwrap() + } +} + +impl SseDecode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() + } +} + +impl SseDecode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} +} + +impl SseDecode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i32::().unwrap() + } +} + +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +fn pde_ffi_dispatcher_primary_impl( + func_id: i32, + port: flutter_rust_bridge::for_generated::MessagePort, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + _ => unreachable!(), + } +} + +fn pde_ffi_dispatcher_sync_impl( + func_id: i32, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 1 => wire__crate__api__bip85__derive_impl(ptr, rust_vec_len, data_len), + 2 => wire__crate__api__bip85__to_base64_impl(ptr, rust_vec_len, data_len), + 3 => wire__crate__api__bip85__to_base85_impl(ptr, rust_vec_len, data_len), + 4 => wire__crate__api__bip85__to_hex_impl(ptr, rust_vec_len, data_len), + 5 => wire__crate__api__bip85__to_mnemonic_impl(ptr, rust_vec_len, data_len), + 6 => wire__crate__api__bip85__to_mnemonic_in_impl(ptr, rust_vec_len, data_len), + 7 => wire__crate__api__bip85__to_wif_impl(ptr, rust_vec_len, data_len), + 8 => wire__crate__api__bip85__to_xprv_impl(ptr, rust_vec_len, data_len), + _ => unreachable!(), + } +} + +// Section: rust2dart + +impl SseEncode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_bytes(), serializer); + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u32::(self).unwrap(); + } +} + +impl SseEncode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self).unwrap(); + } +} + +impl SseEncode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + +impl SseEncode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i32::(self).unwrap(); + } +} + +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +#[cfg(not(target_family = "wasm"))] +mod io { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.9.0. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_io!(); +} +#[cfg(not(target_family = "wasm"))] +pub use io::*; + +/// cbindgen:ignore +#[cfg(target_family = "wasm")] +mod web { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.9.0. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::wasm_bindgen; + use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_web!(); +} +#[cfg(target_family = "wasm")] +pub use web::*; diff --git a/bindings/dart-bip85/rust/src/frb_generated.web.rs b/bindings/dart-bip85/rust/src/frb_generated.web.rs new file mode 100644 index 0000000..7ccbbf3 --- /dev/null +++ b/bindings/dart-bip85/rust/src/frb_generated.web.rs @@ -0,0 +1,15 @@ +// This file is automatically generated, so please do not edit it. +// Generated by `flutter_rust_bridge`@ 2.0.0. + +// Section: imports + +use super::*; +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::wasm_bindgen; +use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate_web!(); diff --git a/bindings/dart-bip85/rust/src/lib.rs b/bindings/dart-bip85/rust/src/lib.rs new file mode 100644 index 0000000..a7dcbb7 --- /dev/null +++ b/bindings/dart-bip85/rust/src/lib.rs @@ -0,0 +1,8 @@ +pub mod api; +mod frb_generated; + +#[flutter_rust_bridge::frb(init)] +pub fn init_app() { + // Default utilities - feel free to customize + flutter_rust_bridge::setup_default_user_utils(); +} diff --git a/bindings/dart-bip85/test_driver/integration_test.dart b/bindings/dart-bip85/test_driver/integration_test.dart new file mode 100644 index 0000000..b38629c --- /dev/null +++ b/bindings/dart-bip85/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/bindings/dart-bip85/windows/.gitignore b/bindings/dart-bip85/windows/.gitignore new file mode 100644 index 0000000..b3eb2be --- /dev/null +++ b/bindings/dart-bip85/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/bindings/dart-bip85/windows/CMakeLists.txt b/bindings/dart-bip85/windows/CMakeLists.txt new file mode 100644 index 0000000..8645c91 --- /dev/null +++ b/bindings/dart-bip85/windows/CMakeLists.txt @@ -0,0 +1,20 @@ +# The Flutter tooling requires that developers have a version of Visual Studio +# installed that includes CMake 3.14 or later. You should not increase this +# version, as doing so will cause the plugin to fail to compile for some +# customers of the plugin. +cmake_minimum_required(VERSION 3.14) + +# Project-level configuration. +set(PROJECT_NAME "bip85") +project(${PROJECT_NAME} LANGUAGES CXX) + +include("../cargokit/cmake/cargokit.cmake") +apply_cargokit(${PROJECT_NAME} ../rust bip85 "") + +# 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(bip85_bundled_libraries + "${${PROJECT_NAME}_cargokit_lib}" + PARENT_SCOPE +) diff --git a/examples/drng.rs b/examples/drng.rs new file mode 100644 index 0000000..fec6838 --- /dev/null +++ b/examples/drng.rs @@ -0,0 +1,21 @@ +use bitcoin::{ + bip32::{DerivationPath, Xpriv}, + hex::DisplayHex, + key::Secp256k1, +}; +use std::str::FromStr; + +use bip85_extended::*; + +fn main() { + let xprv = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); + let path = DerivationPath::from_str("m/0'/0'").unwrap(); + let derived = bip85_extended::derive(&Secp256k1::new(), &xprv, &path).unwrap(); + let entropy: [u8; 64] = derived.try_into().unwrap(); + println!("Entropy: {}", entropy.clone().to_lower_hex_string()); + + let mut drng_reader = bip85_extended::DRNG::new(entropy); + let mut drng_80_bytes = [0u8; 80]; + drng_reader.read(&mut drng_80_bytes); + println!("DRNG: {}", drng_80_bytes.to_lower_hex_string()); +} diff --git a/examples/mnemonic.rs b/examples/mnemonic.rs index 671bd24..20bad08 100644 --- a/examples/mnemonic.rs +++ b/examples/mnemonic.rs @@ -1,24 +1,25 @@ -extern crate bip85; +extern crate bip85_extended; use std::str::FromStr; -use bitcoin::secp256k1::Secp256k1; -use bitcoin::util::bip32::ExtendedPrivKey; use bip39::Language; +use bitcoin::bip32::Xpriv; +use bitcoin::secp256k1::Secp256k1; -fn main(){ - let root = ExtendedPrivKey::from_str( +fn main() { + let root = Xpriv::from_str( "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); let secp = Secp256k1::new(); - let mnemonic = bip85::to_mnemonic(&secp, &root, 12, 0).unwrap(); + let mnemonic = bip85_extended::to_mnemonic(&secp, &root, 12, 0).unwrap(); println!("12-word mnemonic:\n{}", mnemonic); - let mnemonic = bip85::to_mnemonic(&secp, &root, 24, 0).unwrap(); + let mnemonic = bip85_extended::to_mnemonic(&secp, &root, 24, 0).unwrap(); println!("24-word mnemonic:\n{}", mnemonic); - let mnemonic = bip85::to_mnemonic_in(&secp, &root, Language::Japanese, 18, 0).unwrap(); + let mnemonic = bip85_extended::to_mnemonic_in(&secp, &root, Language::Japanese, 18, 0).unwrap(); println!("18-word mnemonic in Japanese:\n{}", mnemonic); } diff --git a/examples/simple.rs b/examples/simple.rs index bd3abc9..acdec3d 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,23 +1,27 @@ -extern crate bip85; +extern crate bip85_extended; use std::str::FromStr; +use bitcoin::bip32::Xpriv; use bitcoin::secp256k1::Secp256k1; -use bitcoin::util::bip32::ExtendedPrivKey; -fn main(){ - let root = ExtendedPrivKey::from_str( +fn main() { + let root = Xpriv::from_str( "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); let secp = Secp256k1::new(); - let derived = bip85::to_wif(&secp, &root, 0).unwrap(); + let derived = bip85_extended::to_wif(&secp, &root, 0).unwrap(); println!("WIF key:\n{}", derived); - let data = bip85::to_hex(&secp, &root, 35, 0).unwrap(); + let data = bip85_extended::to_hex(&secp, &root, 35, 0).unwrap(); println!("35 bytes of hex entropy:\n{:x?}", data); - let xprv = bip85::to_xprv(&secp, &root, 0).unwrap(); + let xprv = bip85_extended::to_xprv(&secp, &root, 0).unwrap(); println!("Derived extended private key:\n{}", xprv); + + let nsec = bip85_extended::to_nostr(&secp, &root, 1, 1).unwrap(); + println!("Nostr nsec (identity=1, account=1):\n{}", nsec); } diff --git a/src/drng.rs b/src/drng.rs new file mode 100644 index 0000000..92d499f --- /dev/null +++ b/src/drng.rs @@ -0,0 +1,50 @@ +use sha3::{ + digest::{core_api::XofReaderCoreWrapper, ExtendableOutput, Update}, + Shake256, Shake256ReaderCore, +}; + +/// BIP85-DRNG-SHAKE256 is a deterministic random number generator for cryptographic functions that require deterministic outputs, but where the input to that function requires more than the 64 bytes provided by BIP85's HMAC output. +/// BIP85-DRNG-SHAKE256 uses BIP85 to seed a SHAKE256 stream (from the SHA-3 standard). +/// +/// The input must be exactly 64 bytes long. +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#bip85-drng) for more info. +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use std::str::FromStr; +/// use bitcoin::{ +/// bip32::{DerivationPath, Xpriv}, +/// hex::DisplayHex, +/// key::Secp256k1, +/// }; +/// +/// let xprv = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let path = DerivationPath::from_str("m/0'/0'").unwrap(); +/// let derived = derive(&Secp256k1::new(), &xprv, &path).unwrap(); +/// let entropy: [u8; 64] = derived.try_into().unwrap(); +/// println!("Entropy: {}", entropy.clone().to_lower_hex_string()); +/// +/// let mut drng_reader = DRNG::new(entropy); +/// let mut drng_80_bytes = [0u8; 80]; +/// drng_reader.read(&mut drng_80_bytes); +/// println!("DRNG: {}", drng_80_bytes.to_lower_hex_string()); +/// ``` +pub struct DRNG { + reader: XofReaderCoreWrapper, +} + +impl DRNG { + pub fn new(entropy: [u8; 64]) -> Self { + let mut hasher = Shake256::default(); + hasher.update(&entropy); + DRNG { + reader: hasher.finalize_xof(), + } + } + + pub fn read(&mut self, buffer: &mut [u8]) { + sha3::digest::XofReader::read(&mut self.reader, buffer); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..7e26a78 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,40 @@ +use std::fmt; + +/// A BIP85 error. +#[derive(Clone, PartialEq, Eq)] +pub enum Error { + /// Hardened index is provided, but only non-hardened indexes are allowed + InvalidIndex(u32), + /// Wrong number of bytes requested + InvalidLength(u32), + /// Wrong number of words for mnemonic + InvalidWordCount(u32), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::InvalidIndex(index) => write!( + f, + "invalid index for derivation, should be less than 0x80000000: {}", + index, + ), + Error::InvalidLength(len) => write!( + f, + "invalid bytes length: {}. Should be between 16 and 64", + len, + ), + Error::InvalidWordCount(word_count) => write!( + f, + "invalid number of words for mnemonic: {}. Should be 12, 18 or 24", + word_count, + ), + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} diff --git a/src/hex.rs b/src/hex.rs new file mode 100644 index 0000000..4586e0b --- /dev/null +++ b/src/hex.rs @@ -0,0 +1,42 @@ +use super::Error; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::hex::DisplayHex; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +/// Derive entropy into hexadecimal +/// +/// The `length` can be from 16 to 64 and defines number of bytes derived. +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#hex) for more info. +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// let derived = to_hex(&secp, &root, 64, 0).unwrap(); +/// ``` +pub fn to_hex( + secp: &Secp256k1, + root: &Xpriv, + length: u32, + index: u32, +) -> Result { + const HEX_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 128169 }; + if length < 16 || length > 64 { + return Err(Error::InvalidLength(length)); + } + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + let path = DerivationPath::from(vec![ + HEX_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(length).unwrap(), + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + Ok(data[0..length as usize].to_lower_hex_string()) +} diff --git a/src/lib.rs b/src/lib.rs index aab384c..163848a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ // Rust implementation of bip-85 -// Written in 2020 by -// Rita Kitic +// Initial work in 2020 by Rita Kitic +// Maintained in 2024 by J. Azad EMERY //! # BIP-85 deterministic entropy generation //! @@ -9,7 +9,7 @@ //! //! # Examples //! -//! There are a few [examples](https://github.com/rikitau/rust-bip85/tree/master/examples) +//! There are a few [examples](https://github.com/ethicnology/rust-bip85/tree/master/examples) //! in the repository. //! //! # Optional features @@ -20,378 +20,54 @@ //! All bip-39 languages except english are also optional, so if you plan generating mnemonics in //! japanese enable feature "japanese", and so on. -#![deny(non_upper_case_globals)] -#![deny(non_camel_case_types)] -#![deny(non_snake_case)] -#![deny(unused_mut)] -#![deny(dead_code)] -#![deny(unused_imports)] -#![deny(missing_docs)] - -pub extern crate bitcoin; #[cfg(feature = "mnemonic")] pub extern crate bip39; +pub extern crate bitcoin; -use std::fmt; -use std::default::Default; - -use bitcoin::secp256k1::{self, Secp256k1, SecretKey}; -use bitcoin::util::bip32; -use bitcoin::util::bip32::ExtendedPrivKey; -use bitcoin::util::bip32::DerivationPath; -use bitcoin::util::bip32::ChildNumber; -use bitcoin::util::key::PrivateKey; +pub mod drng; +pub mod error; +pub mod hex; +pub mod mnemonic; +pub mod nostr; +pub mod pwd_base64; +pub mod pwd_base85; +pub mod wif; +pub mod xprv; + +pub use drng::*; +pub use error::Error; +pub use hex::*; +pub use mnemonic::*; +pub use nostr::*; +pub use pwd_base64::*; +pub use pwd_base85::*; +pub use wif::*; +pub use xprv::*; + +use bitcoin::bip32::ChildNumber; +use bitcoin::bip32::Xpriv; use bitcoin::hashes::{hmac, sha512, Hash, HashEngine}; +use bitcoin::secp256k1::{self, Secp256k1}; -#[cfg(feature = "mnemonic")] -use bip39::Mnemonic; -#[cfg(feature = "mnemonic")] -use bip39::Language; - -/// A BIP85 error. -#[derive(Clone, PartialEq, Eq)] -pub enum Error { - /// Hardened index is provided, but only non-hardened indexes are allowed - InvalidIndex(u32), - /// Wrong number of bytes requested - InvalidLength(u32), - /// Wrong number of words for mnemonic - InvalidWordCount(u32), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidIndex(index) => write!(f, - "invalid index for derivation, should be less than 0x80000000: {}", index, - ), - Error::InvalidLength(len) => write!(f, - "invalid bytes length: {}. Should be between 16 and 64", len, - ), - Error::InvalidWordCount(word_count) => write!(f, - "invalid number of words for mnemonic: {}. Should be 12, 18 or 24", word_count, - ), - } - } -} -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - - -/// Derive raw bytes from the root key using provided derivation path. +/// Derive raw bytes from the root inner using provided derivation path. /// /// Use this function only for custom applications, /// for standardized applications use application-specific functions - `to_wif`, /// `to_hex`, `to_xprv` and `to_mnemonic[_in]`. /// /// Derivation path should start *after* initial bip85 index (`83696968'`) -/// For example, to get entropy for WIF private key (app_no `2`) with index `1` +/// For example, to get entropy for WIF private inner (app_no `2`) with index `1` /// use `DerivationPath::from_str("m/2'/0'")`. pub fn derive>( - secp: &Secp256k1, - root: &ExtendedPrivKey, - path: &P, - ) -> Result, Error> { - const BIP85_CHILD_NUMBER: ChildNumber = ChildNumber::Hardened{ index: 83696968 }; - let bip85_root = root.ckd_priv(secp, BIP85_CHILD_NUMBER).unwrap(); + secp: &Secp256k1, + root: &Xpriv, + path: &P, +) -> Result, Error> { + const BIP85_CHILD_NUMBER: ChildNumber = ChildNumber::Hardened { index: 83696968 }; + let bip85_root = root.derive_priv(secp, &vec![BIP85_CHILD_NUMBER]).unwrap(); let derived = bip85_root.derive_priv(secp, &path).unwrap(); let mut h = hmac::HmacEngine::::new("bip-entropy-from-k".as_bytes()); - h.input(&derived.private_key.to_bytes()); - let data = hmac::Hmac::from_engine(h).into_inner(); - Ok(data.to_vec()) -} - - -/// Derive Bitcoin Private Key from the root key -/// -/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#hd-seed-wif) -/// for more info. -/// -/// `index` can be any number lower than `0x80000000` -pub fn to_wif( - secp: &Secp256k1, - root: &ExtendedPrivKey, - index: u32, - ) -> Result { - const BIP85_WIF_INDEX: ChildNumber = ChildNumber::Hardened{ index: 2 }; - if index >= 0x80000000 { - return Err(Error::InvalidIndex(index)); - } - let path = DerivationPath::from(vec![BIP85_WIF_INDEX, - ChildNumber::from_hardened_idx(index).unwrap()]); - let data = derive(secp, root, &path)?; - Ok(PrivateKey { - compressed: true, - network: root.network, - key: SecretKey::from_slice(&data[0..32]).unwrap(), - }) -} - -/// Derive bip32 extended private key from root xprv -/// -/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#xprv) for more info. -/// -/// `index` can be any number lower than `0x80000000` -pub fn to_xprv( - secp: &Secp256k1, - root: &ExtendedPrivKey, - index: u32, - ) -> Result { - const BIP85_BIP32_INDEX: ChildNumber = ChildNumber::Hardened{ index: 32 }; - if index >= 0x80000000 { - return Err(Error::InvalidIndex(index)); - } - let path = DerivationPath::from(vec![BIP85_BIP32_INDEX, - ChildNumber::from_hardened_idx(index).unwrap()]); - let data = derive(secp, root, &path)?; - Ok(ExtendedPrivKey { - network: root.network, - depth: 0, - parent_fingerprint: Default::default(), - child_number: ChildNumber::Normal{index: 0}, - private_key: PrivateKey { - compressed: true, - network: root.network, - key: SecretKey::from_slice( - &data[32..] - ).unwrap(), - }, - chain_code: bip32::ChainCode::from(&data[..32]), - }) -} - -/// Derive binary entropy of certain length from the root key -/// -/// The `length` can be from 16 to 64 and defines number of bytes derived. -/// -/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#hex) for more info. -pub fn to_hex( - secp: &Secp256k1, - root: &ExtendedPrivKey, - length: u32, - index: u32, - ) -> Result, Error> { - const BIP85_HEX_INDEX: ChildNumber = ChildNumber::Hardened{ index: 128169 }; - if length < 16 || length > 64 { - return Err(Error::InvalidLength(length)); - } - if index >= 0x80000000 { - return Err(Error::InvalidIndex(index)); - } - let path = DerivationPath::from(vec![BIP85_HEX_INDEX, - ChildNumber::from_hardened_idx(length).unwrap(), - ChildNumber::from_hardened_idx(index).unwrap() - ]); - let data = derive(secp, root, &path)?; - Ok(data[0..length as usize].to_vec()) -} - -#[cfg(feature = "mnemonic")] -/// Derive mnemonic in given language -/// -/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#bip39) -/// for more info. -/// -/// `word_count` can be 12, 18 or 24, `index` - anything lower than `0x80000000` -pub fn to_mnemonic_in( - secp: &Secp256k1, - root: &ExtendedPrivKey, - lang: Language, - word_count: u32, - index: u32, - ) -> Result{ - if word_count < 12 || word_count > 24 || word_count % 6 != 0 { - return Err(Error::InvalidWordCount(word_count)); - } - if index >= 0x80000000 { - return Err(Error::InvalidIndex(index)); - } - const BIP85_BIP39_INDEX: ChildNumber = ChildNumber::Hardened{ index: 39 }; - let language_index = match lang { - Language::English => 0, - #[cfg(feature = "japanese")] - Language::Japanese => 1, - #[cfg(feature = "korean")] - Language::Korean => 2, - #[cfg(feature = "spanish")] - Language::Spanish => 3, - #[cfg(feature = "chinese-simplified")] - Language::SimplifiedChinese => 4, - #[cfg(feature = "chinese-traditional")] - Language::TraditionalChinese => 5, - #[cfg(feature = "french")] - Language::French => 6, - #[cfg(feature = "italian")] - Language::Italian => 7, - #[cfg(feature = "czech")] - Language::Czech => 8, - }; - let path = DerivationPath::from(vec![BIP85_BIP39_INDEX, - ChildNumber::Hardened { index: language_index }, - ChildNumber::from_hardened_idx(word_count).unwrap(), - ChildNumber::from_hardened_idx(index).unwrap() - ]); - let data = derive(secp, root, &path)?; - let len = word_count * 4 / 3; - let mnemonic = Mnemonic::from_entropy_in(lang, &data[0..len as usize]).unwrap(); - Ok(mnemonic) -} -/// Derive mnemonic from the xprv key -/// -/// Same as `to_mnemonic_in` using English language as default. -/// -/// `word_count` can be 12, 18 or 24, `index` - anything lower than `0x80000000` -#[cfg(feature = "mnemonic")] -pub fn to_mnemonic( - secp: &Secp256k1, - root: &ExtendedPrivKey, - word_count: u32, - index: u32, - ) -> Result{ - to_mnemonic_in(secp, root, Language::English, word_count, index) -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::str::FromStr; - use bitcoin::secp256k1::Secp256k1; - use bitcoin::util::bip32::{ExtendedPrivKey,DerivationPath}; - use bitcoin::util::key::PrivateKey; - - // test vectors from https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki - #[test] - fn test_raw() { - let root = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); - let secp = Secp256k1::new(); - - let path = DerivationPath::from_str("m/0'/0'").unwrap(); - let derived = derive(&secp, &root, &path).unwrap(); - let expected = vec![0xef, 0xec, 0xfb, 0xcc, 0xff, 0xea, 0x31, 0x32, - 0x14, 0x23, 0x2d, 0x29, 0xe7, 0x15, 0x63, 0xd9, - 0x41, 0x22, 0x9a, 0xfb, 0x43, 0x38, 0xc2, 0x1f, - 0x95, 0x17, 0xc4, 0x1a, 0xaa, 0x0d, 0x16, 0xf0, - 0x0b, 0x83, 0xd2, 0xa0, 0x9e, 0xf7, 0x47, 0xe7, - 0xa6, 0x4e, 0x8e, 0x2b, 0xd5, 0xa1, 0x48, 0x69, - 0xe6, 0x93, 0xda, 0x66, 0xce, 0x94, 0xac, 0x2d, - 0xa5, 0x70, 0xab, 0x7e, 0xe4, 0x86, 0x18, 0xf7, - ]; - assert_eq!(expected, derived); - - let path = DerivationPath::from_str("m/0'/1'").unwrap(); - let derived = derive(&secp, &root, &path).unwrap(); - let expected = vec![0x70, 0xc6, 0xe3, 0xe8, 0xeb, 0xee, 0x8d, 0xc4, - 0xc0, 0xdb, 0xba, 0x66, 0x07, 0x68, 0x19, 0xbb, - 0x8c, 0x09, 0x67, 0x25, 0x27, 0xc4, 0x27, 0x7c, - 0xa8, 0x72, 0x95, 0x32, 0xad, 0x71, 0x18, 0x72, - 0x21, 0x8f, 0x82, 0x69, 0x19, 0xf6, 0xb6, 0x72, - 0x18, 0xad, 0xde, 0x99, 0x01, 0x8a, 0x6d, 0xf9, - 0x09, 0x5a, 0xb2, 0xb5, 0x8d, 0x80, 0x3b, 0x5b, - 0x93, 0xec, 0x98, 0x02, 0x08, 0x5a, 0x69, 0x0e, - ]; - assert_eq!(expected, derived); - } - - #[test] - fn test_priv() { - let root = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); - let secp = Secp256k1::new(); - let derived = to_wif(&secp, &root, 0).unwrap(); - let expected = PrivateKey::from_str( - "Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp" - ).unwrap(); - - assert_eq!(expected, derived); - - let index = 0x80000000+1; - let derived = to_wif(&secp, &root, index); - assert_eq!(derived, Err(Error::InvalidIndex(index))); - } - - #[test] - fn test_xprv() { - let root = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); - let secp = Secp256k1::new(); - - let derived = to_xprv(&secp, &root, 0).unwrap(); - let expected = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UG\ - XMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX" - ).unwrap(); - - assert_eq!(expected, derived); - } - - #[test] - fn test_hex() { - let root = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); - let secp = Secp256k1::new(); - let derived = to_hex(&secp, &root, 64, 0).unwrap(); - let expected = vec![0x49, 0x2d, 0xb4, 0x69, 0x8c, 0xf3, 0xb7, 0x3a, - 0x5a, 0x24, 0x99, 0x8a, 0xa3, 0xe9, 0xd7, 0xfa, - 0x96, 0x27, 0x5d, 0x85, 0x72, 0x4a, 0x91, 0xe7, - 0x1a, 0xa2, 0xd6, 0x45, 0x44, 0x2f, 0x87, 0x85, - 0x55, 0xd0, 0x78, 0xfd, 0x1f, 0x1f, 0x67, 0xe3, - 0x68, 0x97, 0x6f, 0x04, 0x13, 0x7b, 0x1f, 0x7a, - 0x0d, 0x19, 0x23, 0x21, 0x36, 0xca, 0x50, 0xc4, - 0x46, 0x14, 0xaf, 0x72, 0xb5, 0x58, 0x2a, 0x5c, - ]; - - assert_eq!(expected, derived); - - let derived = to_hex(&secp, &root, 35, 0).unwrap(); - assert_eq!(derived.len(), 35); - - let derived = to_hex(&secp, &root, 15, 0); - assert_eq!(derived, Err(Error::InvalidLength(15))); - - let derived = to_hex(&secp, &root, 65, 0); - assert_eq!(derived, Err(Error::InvalidLength(65))); - } - - #[cfg(feature = "mnemonic")] - #[test] - fn test_mnemonic() { - let root = ExtendedPrivKey::from_str( - "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ - LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" - ).unwrap(); - let secp = Secp256k1::new(); - - let derived = to_mnemonic(&secp, &root, 12, 0).unwrap(); - let expected = Mnemonic::from_str( - "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose" - ).unwrap(); - assert_eq!(derived, expected); - - let derived = to_mnemonic(&secp, &root, 18, 0).unwrap(); - let expected = Mnemonic::from_str( - "near account window bike charge season chef number sketch tomorrow excuse sniff \ - circle vital hockey outdoor supply token" - ).unwrap(); - assert_eq!(derived, expected); - - let derived = to_mnemonic(&secp, &root, 24, 0).unwrap(); - let expected = Mnemonic::from_str( - "puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget \ - divorce twin tonight reason outdoor destroy simple truth cigar social volcano" - ).unwrap(); - assert_eq!(derived, expected); - } + h.input(&derived.private_key.secret_bytes()); + let data = hmac::Hmac::from_engine(h); + Ok(data.to_byte_array().to_vec()) } diff --git a/src/mnemonic.rs b/src/mnemonic.rs new file mode 100644 index 0000000..7407052 --- /dev/null +++ b/src/mnemonic.rs @@ -0,0 +1,99 @@ +#[cfg(feature = "mnemonic")] +use bip39::Language; +#[cfg(feature = "mnemonic")] +use bip39::Mnemonic; + +use super::Error; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +#[cfg(feature = "mnemonic")] +/// Derive entropy into a mnemonic for the in given language +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#bip39) +/// for more info. +/// +/// `word_count` can be 12, 18 or 24, `index` - anything lower than `0x80000000` +pub fn to_mnemonic_in( + secp: &Secp256k1, + root: &Xpriv, + lang: Language, + word_count: u32, + index: u32, +) -> Result { + if word_count < 12 || word_count > 24 || word_count % 6 != 0 { + return Err(Error::InvalidWordCount(word_count)); + } + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + const BIP39_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 39 }; + let language_index = match lang { + Language::English => 0, + #[cfg(feature = "japanese")] + Language::Japanese => 1, + #[cfg(feature = "korean")] + Language::Korean => 2, + #[cfg(feature = "spanish")] + Language::Spanish => 3, + #[cfg(feature = "chinese-simplified")] + Language::SimplifiedChinese => 4, + #[cfg(feature = "chinese-traditional")] + Language::TraditionalChinese => 5, + #[cfg(feature = "french")] + Language::French => 6, + #[cfg(feature = "italian")] + Language::Italian => 7, + #[cfg(feature = "czech")] + Language::Czech => 8, + #[cfg(feature = "portuguese")] + Language::Portuguese => 9, + }; + let path = DerivationPath::from(vec![ + BIP39_APPLICATION_NUMBER, + ChildNumber::Hardened { + index: language_index, + }, + ChildNumber::from_hardened_idx(word_count).unwrap(), + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + let len = word_count * 4 / 3; + let mnemonic = Mnemonic::from_entropy_in(lang, &data[0..len as usize]).unwrap(); + Ok(mnemonic) +} + +/// Derive mnemonic from the xprv inner +/// +/// Same as `to_mnemonic_in` using English language as default. +/// +/// `word_count` can be 12, 18 or 24, `index` - anything lower than `0x80000000` +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use std::str::FromStr; +/// use bitcoin::{ +/// bip32::Xpriv, +/// hex::DisplayHex, +/// key::Secp256k1, +/// }; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// +/// let mnemonic = to_mnemonic(&secp, &root, 12, 0).unwrap(); +/// println!("12-word english mnemonic:\n{}", mnemonic); +/// +/// let mnemonic = to_mnemonic(&secp, &root, 24, 0).unwrap(); +/// println!("24-word english mnemonic:\n{}", mnemonic); +/// ``` +#[cfg(feature = "mnemonic")] +pub fn to_mnemonic( + secp: &Secp256k1, + root: &Xpriv, + word_count: u32, + index: u32, +) -> Result { + to_mnemonic_in(secp, root, Language::English, word_count, index) +} diff --git a/src/nostr.rs b/src/nostr.rs new file mode 100644 index 0000000..c3aec4d --- /dev/null +++ b/src/nostr.rs @@ -0,0 +1,86 @@ +use super::Error; +use bitcoin::bech32::{self, Bech32, Hrp}; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +const NOSTR_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 9000 }; + +/// Derive a Nostr private key as an `nsec` Bech32 string (NIP19) using BIP85. +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#nostr) +/// for more info. +/// +/// Path format: `m/83696968'/9000'/{identity}'/{account}'`. +/// +/// Per the spec, `identity = 0'` is reserved for future protocol use and +/// `account = 0'` is reserved across all identities for key management +/// operations; usable keys start at `identity >= 1'` and `account >= 1'`. +/// This function will still derive zero-indexed children — callers that want +/// to enforce the "usable" convention must check the arguments themselves. +/// +/// Both `identity` and `account` must be lower than `0x80000000` +/// (hardened-index range). +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// let nsec = to_nostr(&secp, &root, 1, 1).unwrap(); +/// assert_eq!(nsec, "nsec1254dr4tclcdujf7we9sjv5t99vru2tw7gqtezx7z80y4x45qwhlsmxapst"); +/// ``` +pub fn to_nostr( + secp: &Secp256k1, + root: &Xpriv, + identity: u32, + account: u32, +) -> Result { + let key = to_nostr_bytes(secp, root, identity, account)?; + let hrp = Hrp::parse("nsec").expect("nsec is a valid HRP"); + Ok(bech32::encode::(hrp, &key).expect("32-byte payload fits in Bech32 limits")) +} + +/// Derive the 32-byte Nostr private key bytes using BIP85, without Bech32 encoding. +/// +/// This is the most significant 32 bytes of the BIP85 HMAC output for path +/// `m/83696968'/9000'/{identity}'/{account}'`. +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1, hex::DisplayHex}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// let key = to_nostr_bytes(&secp, &root, 1, 1).unwrap(); +/// assert_eq!( +/// key.to_lower_hex_string(), +/// "552ad1d578fe1bc927cec9612651652b07c52dde4017911bc23bc953568075ff", +/// ); +/// ``` +pub fn to_nostr_bytes( + secp: &Secp256k1, + root: &Xpriv, + identity: u32, + account: u32, +) -> Result<[u8; 32], Error> { + if identity >= 0x80000000 { + return Err(Error::InvalidIndex(identity)); + } + if account >= 0x80000000 { + return Err(Error::InvalidIndex(account)); + } + let path = DerivationPath::from(vec![ + NOSTR_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(identity).unwrap(), + ChildNumber::from_hardened_idx(account).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + let mut out = [0u8; 32]; + out.copy_from_slice(&data[..32]); + Ok(out) +} diff --git a/src/pwd_base64.rs b/src/pwd_base64.rs new file mode 100644 index 0000000..5208af7 --- /dev/null +++ b/src/pwd_base64.rs @@ -0,0 +1,44 @@ +use super::Error; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +/// Derive entropy into base64 +/// +/// The `length` can be from 20 to 86 and defines number of bytes derived. +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#pwd-base64) for more info. +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let pwd_base64 = to_pwd_base64(&Secp256k1::new(), &root, 21, 0).unwrap(); +/// ``` +pub fn to_pwd_base64( + secp: &Secp256k1, + root: &Xpriv, + length: u32, + index: u32, +) -> Result { + const PWD_BASE64_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 707764 }; + if length < 20 || length > 86 { + return Err(Error::InvalidLength(length)); + } + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + let path = DerivationPath::from(vec![ + PWD_BASE64_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(length).unwrap(), + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + let mut pwd = BASE64_STANDARD.encode(data); + pwd.truncate(length.try_into().unwrap()); + Ok(pwd) +} diff --git a/src/pwd_base85.rs b/src/pwd_base85.rs new file mode 100644 index 0000000..a18a614 --- /dev/null +++ b/src/pwd_base85.rs @@ -0,0 +1,42 @@ +use super::Error; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +/// Derive entropy into base85 +/// +/// The `length` can be from 10 to 80 and defines number of bytes derived. +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#pwd-base85) for more info. +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let pwd_base64 = to_pwd_base85(&Secp256k1::new(), &root, 21, 0).unwrap(); +/// ``` +pub fn to_pwd_base85( + secp: &Secp256k1, + root: &Xpriv, + length: u32, + index: u32, +) -> Result { + const PWD_BASE85_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 707785 }; + if length < 10 || length > 80 { + return Err(Error::InvalidLength(length)); + } + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + let path = DerivationPath::from(vec![ + PWD_BASE85_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(length).unwrap(), + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + let mut pwd = base85::encode(&data); + pwd.truncate(length.try_into().unwrap()); + Ok(pwd) +} diff --git a/src/wif.rs b/src/wif.rs new file mode 100644 index 0000000..517277f --- /dev/null +++ b/src/wif.rs @@ -0,0 +1,43 @@ +use super::Error; +use bitcoin::bip32::{ChildNumber, DerivationPath}; +use bitcoin::secp256k1::SecretKey; +use bitcoin::PrivateKey; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +/// Derive entropy into a Bitcoin Private Key HD-Seed WIF +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#hd-seed-wif) +/// for more info. +/// +/// `index` can be any number lower than `0x80000000` +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// let derived = to_wif(&secp, &root, 0).unwrap(); +/// ``` +pub fn to_wif( + secp: &Secp256k1, + root: &Xpriv, + index: u32, +) -> Result { + const WIF_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 2 }; + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + let path = DerivationPath::from(vec![ + WIF_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + Ok(PrivateKey { + compressed: true, + network: root.network, + inner: SecretKey::from_slice(&data[0..32]).unwrap(), + }) +} diff --git a/src/xprv.rs b/src/xprv.rs new file mode 100644 index 0000000..5c6c3df --- /dev/null +++ b/src/xprv.rs @@ -0,0 +1,46 @@ +use bitcoin::bip32::{self, ChildNumber, DerivationPath}; +use bitcoin::secp256k1::SecretKey; +use bitcoin::{bip32::Xpriv, key::Secp256k1, secp256k1}; + +use super::Error; + +/// Derive bip32 extended private key +/// +/// See [specs](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#xprv) for more info. +/// +/// `index` can be any number lower than `0x80000000` +/// +/// ### Example +/// ```rust +/// use bip85_extended::*; +/// use bitcoin::{bip32::Xpriv, key::Secp256k1}; +/// use std::str::FromStr; +/// +/// let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); +/// let secp = Secp256k1::new(); +/// let derived = to_xprv(&secp, &root, 0).unwrap(); +/// ``` +pub fn to_xprv( + secp: &Secp256k1, + root: &Xpriv, + index: u32, +) -> Result { + const BIP32_APPLICATION_NUMBER: ChildNumber = ChildNumber::Hardened { index: 32 }; + if index >= 0x80000000 { + return Err(Error::InvalidIndex(index)); + } + let path = DerivationPath::from(vec![ + BIP32_APPLICATION_NUMBER, + ChildNumber::from_hardened_idx(index).unwrap(), + ]); + let data = crate::derive(secp, root, &path)?; + let chain_code: [u8; 32] = data[..32].try_into().expect(""); + Ok(Xpriv { + network: root.network, + depth: 0, + parent_fingerprint: Default::default(), + child_number: ChildNumber::Normal { index: 0 }, + private_key: SecretKey::from_slice(&data[32..]).unwrap(), + chain_code: bip32::ChainCode::from(chain_code), + }) +} diff --git a/tests/bip85_tests.rs b/tests/bip85_tests.rs new file mode 100644 index 0000000..11205f1 --- /dev/null +++ b/tests/bip85_tests.rs @@ -0,0 +1,126 @@ +use ::bip85_extended::error::Error; + +#[cfg(feature = "mnemonic")] +use bip39::Mnemonic; +use bip85_extended::*; +use bitcoin::bip32::DerivationPath; +use bitcoin::bip32::Xpriv; +use bitcoin::secp256k1::Secp256k1; +use bitcoin::PrivateKey; +use std::str::FromStr; + +// test vectors from https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki +#[test] +fn test_raw() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + let secp = Secp256k1::new(); + + let path = DerivationPath::from_str("m/0'/0'").unwrap(); + let derived = derive(&secp, &root, &path).unwrap(); + let expected = vec![ + 0xef, 0xec, 0xfb, 0xcc, 0xff, 0xea, 0x31, 0x32, 0x14, 0x23, 0x2d, 0x29, 0xe7, 0x15, 0x63, + 0xd9, 0x41, 0x22, 0x9a, 0xfb, 0x43, 0x38, 0xc2, 0x1f, 0x95, 0x17, 0xc4, 0x1a, 0xaa, 0x0d, + 0x16, 0xf0, 0x0b, 0x83, 0xd2, 0xa0, 0x9e, 0xf7, 0x47, 0xe7, 0xa6, 0x4e, 0x8e, 0x2b, 0xd5, + 0xa1, 0x48, 0x69, 0xe6, 0x93, 0xda, 0x66, 0xce, 0x94, 0xac, 0x2d, 0xa5, 0x70, 0xab, 0x7e, + 0xe4, 0x86, 0x18, 0xf7, + ]; + assert_eq!(expected, derived); + + let path = DerivationPath::from_str("m/0'/1'").unwrap(); + let derived = derive(&secp, &root, &path).unwrap(); + let expected = vec![ + 0x70, 0xc6, 0xe3, 0xe8, 0xeb, 0xee, 0x8d, 0xc4, 0xc0, 0xdb, 0xba, 0x66, 0x07, 0x68, 0x19, + 0xbb, 0x8c, 0x09, 0x67, 0x25, 0x27, 0xc4, 0x27, 0x7c, 0xa8, 0x72, 0x95, 0x32, 0xad, 0x71, + 0x18, 0x72, 0x21, 0x8f, 0x82, 0x69, 0x19, 0xf6, 0xb6, 0x72, 0x18, 0xad, 0xde, 0x99, 0x01, + 0x8a, 0x6d, 0xf9, 0x09, 0x5a, 0xb2, 0xb5, 0x8d, 0x80, 0x3b, 0x5b, 0x93, 0xec, 0x98, 0x02, + 0x08, 0x5a, 0x69, 0x0e, + ]; + assert_eq!(expected, derived); +} + +#[test] +fn test_priv() { + let root = Xpriv::from_str("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb").unwrap(); + let secp = Secp256k1::new(); + let derived = to_wif(&secp, &root, 0).unwrap(); + let expected = + PrivateKey::from_str("Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp").unwrap(); + + assert_eq!(expected, derived); + + let index = 0x80000000 + 1; + let derived = to_wif(&secp, &root, index); + assert_eq!(derived, Err(Error::InvalidIndex(index))); +} + +#[test] +fn test_xprv() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + let secp = Secp256k1::new(); + + let derived = to_xprv(&secp, &root, 0).unwrap(); + + let expected = Xpriv::from_str( + "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UG\ + XMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX", + ) + .unwrap(); + + assert_eq!(expected, derived); +} + +#[test] +fn test_hex() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + let secp = Secp256k1::new(); + let derived = to_hex(&secp, &root, 64, 0).unwrap(); + let expected = "492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c"; + assert_eq!(expected, &derived); +} + +#[cfg(feature = "mnemonic")] +#[test] +fn test_mnemonic() { + use mnemonic::to_mnemonic; + + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + let secp = Secp256k1::new(); + + let derived = to_mnemonic(&secp, &root, 12, 0).unwrap(); + let expected = Mnemonic::from_str( + "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose", + ) + .unwrap(); + assert_eq!(derived, expected); + + let derived = to_mnemonic(&secp, &root, 18, 0).unwrap(); + let expected = Mnemonic::from_str( + "near account window bike charge season chef number sketch tomorrow excuse sniff \ + circle vital hockey outdoor supply token", + ) + .unwrap(); + assert_eq!(derived, expected); + + let derived = to_mnemonic(&secp, &root, 24, 0).unwrap(); + let expected = Mnemonic::from_str( + "puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget \ + divorce twin tonight reason outdoor destroy simple truth cigar social volcano", + ) + .unwrap(); + assert_eq!(derived, expected); +} diff --git a/tests/drng_test.rs b/tests/drng_test.rs new file mode 100644 index 0000000..52540a8 --- /dev/null +++ b/tests/drng_test.rs @@ -0,0 +1,37 @@ +use std::str::FromStr; + +use bip85_extended::drng::DRNG; +use bitcoin::{ + bip32::{DerivationPath, Xpriv}, + hex::DisplayHex, + key::Secp256k1, +}; + +#[test] +fn test_drng_80() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaL\ + LHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + let path = DerivationPath::from_str("m/0'/0'").unwrap(); + let entropy = bip85_extended::derive(&Secp256k1::new(), &root, &path).unwrap(); + + let entropy_hex = entropy.to_lower_hex_string(); + let expected = "efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7"; + assert_eq!(expected, entropy_hex); + + let entropy_64_bytes: [u8; 64] = entropy.try_into().unwrap(); + let mut drng_reader = DRNG::new(entropy_64_bytes); + let mut drng_80_bytes = [0u8; 80]; + drng_reader.read(&mut drng_80_bytes); + + let drng_80_hex = drng_80_bytes.to_lower_hex_string(); + let expected = "b78b1ee6b345eae6836c2d53d33c64cdaf9a696487be81b03e822dc84b3f1cd883d7559e53d175f243e4c349e822a957bbff9224bc5dde9492ef54e8a439f6bc8c7355b87a925a37ee405a7502991111"; + assert_eq!(expected, drng_80_hex); + + let mut drng_25_more = [0u8; 25]; + drng_reader.read(&mut drng_25_more); + let expected = "cd2dddaf1883f4e962abf4fb4b31cd28d5cf6b14f6ddcc9c19"; + assert_eq!(expected, drng_25_more.to_lower_hex_string()); +} diff --git a/tests/nostr_test.rs b/tests/nostr_test.rs new file mode 100644 index 0000000..f490bbd --- /dev/null +++ b/tests/nostr_test.rs @@ -0,0 +1,171 @@ +use bip85_extended::*; +use bitcoin::bech32::{self, Bech32, Hrp}; +use bitcoin::bip32::Xpriv; +use bitcoin::hex::DisplayHex; +use bitcoin::secp256k1::Secp256k1; +use std::str::FromStr; + +// Official BIP85 Nostr (application 9000') test vectors from +// https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#nostr +const MASTER_XPRV: &str = + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"; + +struct SpecVector { + identity: u32, + account: u32, + entropy_hex: &'static str, + nsec: &'static str, +} + +const SPEC_VECTORS: &[SpecVector] = &[ + SpecVector { + identity: 1, + account: 1, + entropy_hex: "552ad1d578fe1bc927cec9612651652b07c52dde4017911bc23bc953568075ff", + nsec: "nsec1254dr4tclcdujf7we9sjv5t99vru2tw7gqtezx7z80y4x45qwhlsmxapst", + }, + SpecVector { + identity: 1, + account: 2, + entropy_hex: "4fd36c0061a65db375b4350f44bb62a6d7f716ee93bd0f59887ac50b35fa8b96", + nsec: "nsec1flfkcqrp5ewmxad5x585fwmz5mtlw9hwjw7s7kvg0tzskd063wtq34wlgr", + }, + SpecVector { + identity: 2, + account: 1, + entropy_hex: "b2d3b48992d46f98beac0196c4e258417087e467dbec1503342785368f4402c2", + nsec: "nsec1ktfmfzvj63he304vqxtvfcjcg9cg0er8m0kp2qe5y7zndr6yqtpq7q5y44", + }, +]; + +fn root() -> Xpriv { + Xpriv::from_str(MASTER_XPRV).unwrap() +} + +#[test] +fn test_nostr_spec_vectors() { + let secp = Secp256k1::new(); + let root = root(); + for v in SPEC_VECTORS { + let bytes = to_nostr_bytes(&secp, &root, v.identity, v.account).unwrap(); + assert_eq!( + bytes.to_lower_hex_string(), + v.entropy_hex, + "entropy mismatch for identity={}, account={}", + v.identity, + v.account, + ); + + let nsec = to_nostr(&secp, &root, v.identity, v.account).unwrap(); + assert_eq!( + nsec, v.nsec, + "nsec mismatch for identity={}, account={}", + v.identity, v.account, + ); + } +} + +#[test] +fn test_nostr_bytes_and_nsec_are_consistent() { + // The string returned by to_nostr() must be a Bech32 encoding (HRP "nsec") + // of exactly the 32 bytes returned by to_nostr_bytes(). + let secp = Secp256k1::new(); + let root = root(); + for v in SPEC_VECTORS { + let bytes = to_nostr_bytes(&secp, &root, v.identity, v.account).unwrap(); + let nsec = to_nostr(&secp, &root, v.identity, v.account).unwrap(); + + let (hrp, payload) = bech32::decode(&nsec).unwrap(); + assert_eq!(hrp, Hrp::parse("nsec").unwrap()); + assert_eq!(&payload[..], &bytes[..]); + + // Re-encoding the bytes ourselves must yield the same string. + let reencoded = bech32::encode::(Hrp::parse("nsec").unwrap(), &bytes).unwrap(); + assert_eq!(reencoded, nsec); + } +} + +#[test] +fn test_nostr_nsec_format() { + // A NIP19 nsec is always: HRP "nsec" + separator '1' + 52 data chars + + // 6 checksum chars = 63 characters total, all lower-case. + let secp = Secp256k1::new(); + let root = root(); + let nsec = to_nostr(&secp, &root, 1, 1).unwrap(); + assert_eq!(nsec.len(), 63); + assert!(nsec.starts_with("nsec1")); + assert_eq!(nsec, nsec.to_lowercase()); +} + +#[test] +fn test_nostr_rejects_non_hardened_indices() { + let secp = Secp256k1::new(); + let root = root(); + let bad = 0x80000000u32; + assert_eq!( + to_nostr(&secp, &root, bad, 1).unwrap_err(), + Error::InvalidIndex(bad), + ); + assert_eq!( + to_nostr(&secp, &root, 1, bad).unwrap_err(), + Error::InvalidIndex(bad), + ); + assert_eq!( + to_nostr_bytes(&secp, &root, bad, 1).unwrap_err(), + Error::InvalidIndex(bad), + ); + assert_eq!( + to_nostr_bytes(&secp, &root, 1, bad).unwrap_err(), + Error::InvalidIndex(bad), + ); + // u32::MAX is also out of range. + assert!(to_nostr(&secp, &root, u32::MAX, 1).is_err()); +} + +#[test] +fn test_nostr_accepts_boundary_hardened_index() { + // 0x7FFFFFFF is the largest valid hardened-child input (it derives the + // m/.../2147483647' child). It must succeed and produce a 63-char nsec. + let secp = Secp256k1::new(); + let root = root(); + let nsec = to_nostr(&secp, &root, 0x7FFFFFFF, 0x7FFFFFFF).unwrap(); + assert_eq!(nsec.len(), 63); + assert!(nsec.starts_with("nsec1")); +} + +#[test] +fn test_nostr_reserved_zero_indices_still_derive() { + // The spec marks identity/account 0 as "reserved" but doesn't make them + // invalid; the reference (bipsea) lets them through. Mirror that contract. + let secp = Secp256k1::new(); + let root = root(); + let nsec_00 = to_nostr(&secp, &root, 0, 0).unwrap(); + let nsec_01 = to_nostr(&secp, &root, 0, 1).unwrap(); + let nsec_10 = to_nostr(&secp, &root, 1, 0).unwrap(); + let nsec_11 = to_nostr(&secp, &root, 1, 1).unwrap(); + assert!(nsec_00.starts_with("nsec1")); + // Each (identity, account) pair must produce a distinct key. + let unique = [&nsec_00, &nsec_01, &nsec_10, &nsec_11]; + for i in 0..unique.len() { + for j in (i + 1)..unique.len() { + assert_ne!(unique[i], unique[j]); + } + } +} + +#[test] +fn test_nostr_distinct_masters_produce_distinct_keys() { + // Different master xprvs must produce different Nostr keys for the same + // (identity, account). This catches accidental dropping of the master. + let secp = Secp256k1::new(); + let a = Xpriv::from_str(MASTER_XPRV).unwrap(); + // A different mainnet xprv, BIP-32 test vector 1 chain m. + let b = Xpriv::from_str( + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", + ) + .unwrap(); + assert_ne!( + to_nostr(&secp, &a, 1, 1).unwrap(), + to_nostr(&secp, &b, 1, 1).unwrap(), + ); +} diff --git a/tests/pwd_base64_test.rs b/tests/pwd_base64_test.rs new file mode 100644 index 0000000..b1e698a --- /dev/null +++ b/tests/pwd_base64_test.rs @@ -0,0 +1,15 @@ +use std::str::FromStr; + +use bitcoin::{bip32::Xpriv, key::Secp256k1}; + +#[test] +fn test_pwd_base64() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + + let pwd_base64 = bip85_extended::to_pwd_base64(&Secp256k1::new(), &root, 21, 0).unwrap(); + let expected = "dKLoepugzdVJvdL56ogNV"; + assert_eq!(expected, pwd_base64); +} diff --git a/tests/pwd_base85_test.rs b/tests/pwd_base85_test.rs new file mode 100644 index 0000000..6627e45 --- /dev/null +++ b/tests/pwd_base85_test.rs @@ -0,0 +1,15 @@ +use bip85_extended::*; +use bitcoin::{bip32::Xpriv, key::Secp256k1}; +use std::str::FromStr; + +#[test] +fn test_pwd_base85() { + let root = Xpriv::from_str( + "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + ) + .unwrap(); + + let pwd_base64 = to_pwd_base85(&Secp256k1::new(), &root, 12, 0).unwrap(); + let expected = "_s`{TW89)i4`"; + assert_eq!(expected, pwd_base64); +} \ No newline at end of file