From b288b601ceca5850f21daff573ca172f8e1a0b7c Mon Sep 17 00:00:00 2001 From: librelois Date: Sat, 9 Jan 2021 21:12:52 +0100 Subject: [PATCH 1/4] ref(dubp):make really async & rework handle error in a more generic way --- .cargo/config.toml | 3 + Cargo.lock | 71 ++++++++++++++ native/dubp_rs/Cargo.toml | 2 + native/dubp_rs/src/async.rs | 42 +++++++++ native/dubp_rs/src/dewif.rs | 64 +++---------- native/dubp_rs/src/error.rs | 77 +++++++++++++++ native/dubp_rs/src/lib.rs | 168 ++++++++++++++++++--------------- native/dubp_rs/src/mnemonic.rs | 7 +- packages/dubp_rs/lib/dubp.dart | 31 +++--- pubspec.lock | 45 ++++----- 10 files changed, 333 insertions(+), 177 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 native/dubp_rs/src/async.rs create mode 100644 native/dubp_rs/src/error.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..393611e --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[alias] +bd = "make android-dev32" +br = "make" diff --git a/Cargo.lock b/Cargo.lock index 93595d1..2c6ad0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "async-oneshot" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f4770cbbff928c30a991de67fb3976f44d8e3e202f8c79ef91b47006e04904" +dependencies = [ + "futures-micro", +] + [[package]] name = "atty" version = "0.2.14" @@ -245,6 +254,8 @@ dependencies = [ "cbindgen", "dart-bindgen", "dup-crypto", + "fast-threadpool", + "once_cell", "thiserror", ] @@ -270,6 +281,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "fast-threadpool" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccb66774e02743b4be61c19e09bf59de9058e9a7b4096040689003e7a901a3d" +dependencies = [ + "async-oneshot", + "flume", + "num_cpus", +] + +[[package]] +name = "flume" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0362ef9c4c1fa854ff95b4cb78045a86e810d804dc04937961988b45427104a9" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "futures-micro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9325be55c5581082cd110294fa988c1f920bc573ec370ef201e33c469a95a" + [[package]] name = "generic-array" version = "0.14.4" @@ -344,6 +381,15 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.11" @@ -353,6 +399,16 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.5.2" @@ -466,6 +522,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.118" @@ -503,6 +565,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spinning_top" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e529d73e80d64b5f2631f9035113347c578a1c9c7774b83a2b880788459ab36" +dependencies = [ + "lock_api", +] + [[package]] name = "strsim" version = "0.8.0" diff --git a/native/dubp_rs/Cargo.toml b/native/dubp_rs/Cargo.toml index feeb05b..58d56c9 100644 --- a/native/dubp_rs/Cargo.toml +++ b/native/dubp_rs/Cargo.toml @@ -11,6 +11,8 @@ crate-type = ["rlib"] [dependencies] allo-isolate = "0.1.6" dup-crypto = { version = "0.36.0", features = ["dewif", "mnemonic", "mnemonic_french", "rand", "scrypt"] } +fast-threadpool = { version = "0.3.0", default-features = false } +once_cell = { version = "1.3.1", default-features = false, features = ["std"] } thiserror = "1.0.23" [build-dependencies] diff --git a/native/dubp_rs/src/async.rs b/native/dubp_rs/src/async.rs new file mode 100644 index 0000000..b7ce764 --- /dev/null +++ b/native/dubp_rs/src/async.rs @@ -0,0 +1,42 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::*; + +static THREAD_POOL: Lazy> = Lazy::new(|| { + ThreadPool::start(ThreadPoolConfig::low().queue_size(Some(16)), ()).into_sync_handler() +}); + +pub(crate) fn exec_async(port: i64, parse_params: F, async_job: F2) +where + P: 'static + Send + Sync, + F: FnOnce() -> Result, + F2: 'static + Send + Sync + FnOnce(P) -> R, + DartRes: From, +{ + match parse_params() { + Ok(parsed_params) => { + if THREAD_POOL + .launch(move |_| Isolate::new(port).post(DartRes::from(async_job(parsed_params)))) + .is_err() + { + Isolate::new(port).post(DartRes::err("thread pool panicked")); + } + } + Err(e) => { + Isolate::new(port).post(DartRes::err(e)); + } + } +} diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index 7d07565..6e9932c 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -35,16 +35,11 @@ pub(super) fn gen_pin10() -> Result { } pub(super) fn change_pin( - currency: *const raw::c_char, - dewif: *const raw::c_char, - old_pin: *const raw::c_char, - new_pin: *const raw::c_char, + currency: &str, + dewif: &str, + old_pin: &str, + new_pin: &str, ) -> Result { - let currency = char_ptr_to_str(currency)?; - let dewif = char_ptr_to_str(dewif)?; - let old_pin = char_ptr_to_str(old_pin)?; - let new_pin = char_ptr_to_str(new_pin)?; - let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), @@ -62,15 +57,11 @@ pub(super) fn change_pin( } pub(super) fn gen_dewif( - currency: *const raw::c_char, + currency: &str, language: u32, - mnemonic: *const raw::c_char, - pin: *const raw::c_char, + mnemonic: &str, + pin: &str, ) -> Result { - let currency = char_ptr_to_str(currency)?; - let mnemonic = char_ptr_to_str(mnemonic)?; - let pin = char_ptr_to_str(pin)?; - let currency = parse_currency(currency)?; let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?) .map_err(|_| DubpError::WrongLanguage)?; @@ -81,15 +72,7 @@ pub(super) fn gen_dewif( )) } -pub(super) fn get_pubkey( - currency: *const raw::c_char, - dewif: *const raw::c_char, - pin: *const raw::c_char, -) -> Result { - let currency = char_ptr_to_str(currency)?; - let dewif = char_ptr_to_str(dewif)?; - let pin = char_ptr_to_str(pin)?; - +pub(super) fn get_pubkey(currency: &str, dewif: &str, pin: &str) -> Result { let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), @@ -104,17 +87,7 @@ pub(super) fn get_pubkey( } } -pub(super) fn sign( - currency: *const raw::c_char, - dewif: *const raw::c_char, - pin: *const raw::c_char, - msg: *const raw::c_char, -) -> Result { - let currency = char_ptr_to_str(currency)?; - let dewif = char_ptr_to_str(dewif)?; - let pin = char_ptr_to_str(pin)?; - let msg = char_ptr_to_str(msg)?; - +pub(super) fn sign(currency: &str, dewif: &str, pin: &str, msg: &str) -> Result { let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), @@ -130,22 +103,11 @@ pub(super) fn sign( } pub(super) fn sign_several( - currency: *const raw::c_char, - dewif: *const raw::c_char, - pin: *const raw::c_char, - msgs_len: usize, - msgs: *const *const raw::c_char, + currency: &str, + dewif: &str, + pin: &str, + msgs: &[&str], ) -> Result, DubpError> { - let currency = char_ptr_to_str(currency)?; - let dewif = char_ptr_to_str(dewif)?; - let pin = char_ptr_to_str(pin)?; - - let msgs_slice: &[*const raw::c_char] = unsafe { std::slice::from_raw_parts(msgs, msgs_len) }; - let mut msgs = Vec::with_capacity(msgs_len); - for ptr_c_char in msgs_slice { - msgs.push(char_ptr_to_str(*ptr_c_char)?); - } - let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), diff --git a/native/dubp_rs/src/error.rs b/native/dubp_rs/src/error.rs new file mode 100644 index 0000000..63bd5ec --- /dev/null +++ b/native/dubp_rs/src/error.rs @@ -0,0 +1,77 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::*; + +/// Dubp error +#[derive(Debug, Error)] +pub(crate) enum DubpError { + #[error("{0}")] + DewifReadError(DewifReadError), + #[error("I/O error: {0}")] + IoErr(io::Error), + #[error("A given parameter is null")] + NullParamErr, + #[error("fail to generate random bytes")] + RandErr, + #[error("Unknown currency name")] + UnknownCurrencyName, + #[error("Unknown language")] + UnknownLanguage, + #[error("{0}")] + Utf8Error(std::str::Utf8Error), + #[error("Wrong language")] + WrongLanguage, +} + +impl From for DubpError { + fn from(e: io::Error) -> Self { + Self::IoErr(e) + } +} + +pub(crate) struct DartRes(allo_isolate::ffi::DartCObject); +impl DartRes { + pub(crate) fn err(e: E) -> allo_isolate::ffi::DartCObject { + vec![format!("DUBP_RS_ERROR: {}", e.to_string())].into_dart() + } +} +impl IntoDart for DartRes { + fn into_dart(self) -> allo_isolate::ffi::DartCObject { + self.0.into_dart() + } +} +impl From> for DartRes +where + E: ToString, +{ + fn from(res: Result) -> Self { + match res { + Ok(string) => Self(string.into_dart()), + Err(e) => Self(format!("DUBP_RS_ERROR: {}", e.to_string()).into_dart()), + } + } +} +impl From, E>> for DartRes +where + E: ToString, +{ + fn from(res: Result, E>) -> Self { + match res { + Ok(vec_string) => Self(vec_string.into_dart()), + Err(e) => Self(vec![format!("DUBP_RS_ERROR: {}", e.to_string())].into_dart()), + } + } +} diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 8d2f03a..2f29e58 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -15,9 +15,13 @@ #![allow(clippy::missing_safety_doc, clippy::not_unsafe_ptr_arg_deref)] +mod r#async; mod dewif; +mod error; mod mnemonic; +use crate::error::{DartRes, DubpError}; +use crate::r#async::exec_async; use allo_isolate::{IntoDart, Isolate}; use dup_crypto::{ bases::b58::ToBase58, @@ -28,65 +32,11 @@ use dup_crypto::{ }, mnemonic::{Language, Mnemonic, MnemonicType}, }; +use fast_threadpool::{ThreadPool, ThreadPoolConfig, ThreadPoolSyncHandler}; +use once_cell::sync::Lazy; use std::{ffi::CStr, io, os::raw}; use thiserror::Error; -/// Dubp error -#[derive(Debug, Error)] -pub enum DubpError { - #[error("{0}")] - DewifReadError(DewifReadError), - #[error("I/O error: {0}")] - IoErr(io::Error), - #[error("A given parameter is null")] - NullParamErr, - #[error("fail to generate random bytes")] - RandErr, - #[error("Unknown currency name")] - UnknownCurrencyName, - #[error("Unknown language")] - UnknownLanguage, - #[error("{0}")] - Utf8Error(std::str::Utf8Error), - #[error("Wrong language")] - WrongLanguage, -} - -impl From for DubpError { - fn from(e: io::Error) -> Self { - Self::IoErr(e) - } -} - -struct DartRes(allo_isolate::ffi::DartCObject); -impl IntoDart for DartRes { - fn into_dart(self) -> allo_isolate::ffi::DartCObject { - self.0.into_dart() - } -} -impl From> for DartRes -where - E: ToString, -{ - fn from(res: Result) -> Self { - match res { - Ok(string) => Self(vec![string].into_dart()), - Err(e) => Self(vec![String::from("_"), e.to_string()].into_dart()), - } - } -} -impl From, E>> for DartRes -where - E: ToString, -{ - fn from(res: Result, E>) -> Self { - match res { - Ok(vec_string) => Self(vec_string.into_dart()), - Err(e) => Self(vec![String::with_capacity(0), e.to_string()].into_dart()), - } - } -} - pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a str, DubpError> { if c_char_ptr.is_null() { Err(DubpError::NullParamErr) @@ -95,6 +45,28 @@ pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a } } +fn char_ptr_prt_to_vec_str<'a>( + char_ptr_ptr: *const *const raw::c_char, + len: u32, +) -> Result, DubpError> { + let len = len as usize; + let char_ptr_slice: &[*const raw::c_char] = + unsafe { std::slice::from_raw_parts(char_ptr_ptr, len) }; + let mut str_vec = Vec::with_capacity(len); + for char_ptr in char_ptr_slice { + str_vec.push(char_ptr_to_str(*char_ptr)?); + } + Ok(str_vec) +} + +fn u32_to_language(i: u32) -> Result { + match i { + 0 => Ok(Language::English), + 1 => Ok(Language::French), + _ => Err(DubpError::UnknownLanguage), + } +} + #[no_mangle] pub extern "C" fn change_dewif_pin( port: i64, @@ -103,9 +75,17 @@ pub extern "C" fn change_dewif_pin( old_pin: *const raw::c_char, new_pin: *const raw::c_char, ) { - Isolate::new(port).post(DartRes::from(dewif::change_pin( - currency, dewif, old_pin, new_pin, - ))); + exec_async( + port, + || { + let currency = char_ptr_to_str(currency)?; + let dewif = char_ptr_to_str(dewif)?; + let old_pin = char_ptr_to_str(old_pin)?; + let new_pin = char_ptr_to_str(new_pin)?; + Ok((currency, dewif, old_pin, new_pin)) + }, + |(currency, dewif, old_pin, new_pin)| dewif::change_pin(currency, dewif, old_pin, new_pin), + ) } #[no_mangle] @@ -116,9 +96,16 @@ pub extern "C" fn gen_dewif( mnemonic: *const raw::c_char, pin: *const raw::c_char, ) { - Isolate::new(port).post(DartRes::from(dewif::gen_dewif( - currency, language, mnemonic, pin, - ))); + exec_async( + port, + || { + let currency = char_ptr_to_str(currency)?; + let mnemonic = char_ptr_to_str(mnemonic)?; + let pin = char_ptr_to_str(pin)?; + Ok((currency, language, mnemonic, pin)) + }, + |(currency, language, mnemonic, pin)| dewif::gen_dewif(currency, language, mnemonic, pin), + ) } #[no_mangle] @@ -148,7 +135,16 @@ pub extern "C" fn get_dewif_pubkey( dewif: *const raw::c_char, pin: *const raw::c_char, ) { - Isolate::new(port).post(DartRes::from(dewif::get_pubkey(currency, dewif, pin))); + exec_async( + port, + || { + let currency = char_ptr_to_str(currency)?; + let dewif = char_ptr_to_str(dewif)?; + let pin = char_ptr_to_str(pin)?; + Ok((currency, dewif, pin)) + }, + |(currency, dewif, pin)| dewif::get_pubkey(currency, dewif, pin), + ) } #[no_mangle] @@ -157,10 +153,14 @@ pub extern "C" fn mnemonic_to_pubkey( language: u32, mnemonic_phrase: *const raw::c_char, ) { - Isolate::new(port).post(DartRes::from(mnemonic::mnemonic_to_pubkey( - language, - mnemonic_phrase, - ))); + exec_async( + port, + || { + let mnemonic_phrase = char_ptr_to_str(mnemonic_phrase)?; + Ok((language, mnemonic_phrase)) + }, + |(language, mnemonic_phrase)| mnemonic::mnemonic_to_pubkey(language, mnemonic_phrase), + ) } #[no_mangle] @@ -171,7 +171,17 @@ pub extern "C" fn sign( pin: *const raw::c_char, msg: *const raw::c_char, ) { - Isolate::new(port).post(DartRes::from(dewif::sign(currency, dewif, pin, msg))); + exec_async( + port, + || { + let currency = char_ptr_to_str(currency)?; + let dewif = char_ptr_to_str(dewif)?; + let pin = char_ptr_to_str(pin)?; + let msg = char_ptr_to_str(msg)?; + Ok((currency, dewif, pin, msg)) + }, + |(currency, dewif, pin, msg)| dewif::sign(currency, dewif, pin, msg), + ) } #[no_mangle] @@ -180,16 +190,18 @@ pub extern "C" fn sign_several( currency: *const raw::c_char, dewif: *const raw::c_char, pin: *const raw::c_char, - msgs_len: usize, + msgs_len: u32, msgs: *const *const raw::c_char, ) { - Isolate::new(port).post(dewif::sign_several(currency, dewif, pin, msgs_len, msgs)); -} - -fn u32_to_language(i: u32) -> Result { - match i { - 0 => Ok(Language::English), - 1 => Ok(Language::French), - _ => Err(DubpError::UnknownLanguage), - } + exec_async( + port, + || { + let currency = char_ptr_to_str(currency)?; + let dewif = char_ptr_to_str(dewif)?; + let pin = char_ptr_to_str(pin)?; + let msgs = char_ptr_prt_to_vec_str(msgs, msgs_len)?; + Ok((currency, dewif, pin, msgs)) + }, + |(currency, dewif, pin, msgs)| dewif::sign_several(currency, dewif, pin, &msgs), + ) } diff --git a/native/dubp_rs/src/mnemonic.rs b/native/dubp_rs/src/mnemonic.rs index ac17486..765427d 100644 --- a/native/dubp_rs/src/mnemonic.rs +++ b/native/dubp_rs/src/mnemonic.rs @@ -21,12 +21,7 @@ pub(super) fn gen_mnemonic(language: u32) -> Result { Ok(mnemonic.phrase().to_owned()) } -pub(super) fn mnemonic_to_pubkey( - language: u32, - mnemonic: *const raw::c_char, -) -> Result { - let mnemonic = char_ptr_to_str(mnemonic)?; - +pub(super) fn mnemonic_to_pubkey(language: u32, mnemonic: &str) -> Result { let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?) .map_err(|_| DubpError::WrongLanguage)?; let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic); diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index a3384e8..35b4e8a 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -55,7 +55,7 @@ class DubpRust { static Future genMnemonic({Language language = Language.english}) { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.gen_mnemonic( sendPort.nativePort, language.index, @@ -66,7 +66,7 @@ class DubpRust { static Future _genPin(PinLength pinLength) { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); switch (pinLength) { case PinLength.ten: native.gen_pin10( @@ -101,7 +101,7 @@ class DubpRust { { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.change_dewif_pin( sendPort.nativePort, Utf8.toUtf8(currency), @@ -116,7 +116,7 @@ class DubpRust { { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.get_dewif_pubkey( sendPort.nativePort, Utf8.toUtf8(currency), @@ -148,7 +148,7 @@ class DubpRust { { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.mnemonic_to_pubkey( sendPort.nativePort, language.index, @@ -161,7 +161,7 @@ class DubpRust { { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.gen_dewif( sendPort.nativePort, Utf8.toUtf8(currency), @@ -179,7 +179,7 @@ class DubpRust { {String currency = "g1", String dewif, String pin}) async { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.get_dewif_pubkey( sendPort.nativePort, Utf8.toUtf8(currency), @@ -196,7 +196,7 @@ class DubpRust { {String currency = "g1", String dewif, String pin, String message}) { final completer = Completer(); final sendPort = - singleCompletePort(completer, callback: _handleErr); + singleCompletePort(completer, callback: _handleErr); native.sign( sendPort.nativePort, Utf8.toUtf8(currency), @@ -243,21 +243,20 @@ class DubpRust { return ptr; } - static String _handleErr(List res) { - final List arr = res.cast(); - if (arr.length == 1) { - return arr[0]; - } else { - final error = arr[1]; + static String _handleErr(String res) { + if (res.startsWith('DUBP_RS_ERROR: ')) { + final error = res; print(error); throw error; + } else { + return res; } } static List _handleErrList(List res) { final List arr = res.cast(); - if (arr.isNotEmpty && arr[0].isEmpty) { - final error = arr[1]; + if (arr.isNotEmpty && arr[0].startsWith('DUBP_RS_ERROR: ')) { + final error = arr[0]; print(error); throw error; } else { diff --git a/pubspec.lock b/pubspec.lock index 376b9d0..8446555 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,42 +21,42 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.5.0-nullsafety.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0-nullsafety.1" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0-nullsafety.3" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0-nullsafety.1" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0-nullsafety.1" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" + version: "1.15.0-nullsafety.3" connectivity: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0-nullsafety.1" ffi: dependency: transitive description: @@ -282,27 +282,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3-nullsafety.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10-nullsafety.1" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" + version: "1.3.0-nullsafety.3" nested: dependency: transitive description: @@ -330,7 +323,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0-nullsafety.1" path_provider: dependency: "direct main" description: @@ -468,42 +461,42 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.0-nullsafety.2" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0-nullsafety.1" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0-nullsafety.1" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0-nullsafety.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0-nullsafety.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" + version: "0.2.19-nullsafety.2" truncate: dependency: "direct main" description: @@ -517,7 +510,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0-nullsafety.3" uuid: dependency: transitive description: @@ -538,7 +531,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0-nullsafety.3" websocket: dependency: transitive description: @@ -575,5 +568,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.10.0-110 <2.11.0" flutter: ">=1.22.0 <2.0.0" From 63dd4ee59b10dafe247b177609d19be52c8bbb78 Mon Sep 17 00:00:00 2001 From: librelois Date: Sat, 9 Jan 2021 22:03:19 +0100 Subject: [PATCH 2/4] perf(dubp): optimize changeDewifPin & genWalletFromMnemonic --- native/dubp_rs/src/dewif.rs | 44 +++++++------ native/dubp_rs/src/lib.rs | 31 ++++++--- packages/dubp_rs/lib/dubp.dart | 113 ++++++++------------------------- 3 files changed, 70 insertions(+), 118 deletions(-) diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index 6e9932c..6fe856a 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -38,8 +38,8 @@ pub(super) fn change_pin( currency: &str, dewif: &str, old_pin: &str, - new_pin: &str, -) -> Result { + member_wallet: bool, +) -> Result, DubpError> { let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), @@ -48,9 +48,15 @@ pub(super) fn change_pin( ) .map_err(DubpError::DewifReadError)?; if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - Ok(dup_crypto::dewif::write_dewif_v1_content( - currency, &keypair, new_pin, - )) + let new_pin = if member_wallet { + gen_pin10()? + } else { + gen_pin6()? + }; + + let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &new_pin); + let pubkey = keypair.public_key().to_base58(); + Ok(vec![dewif, new_pin, pubkey]) } else { Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) } @@ -60,20 +66,25 @@ pub(super) fn gen_dewif( currency: &str, language: u32, mnemonic: &str, - pin: &str, -) -> Result { + member_wallet: bool, +) -> Result, DubpError> { let currency = parse_currency(currency)?; let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?) .map_err(|_| DubpError::WrongLanguage)?; let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic); let keypair = KeyPairFromSeed32Generator::generate(seed); - Ok(dup_crypto::dewif::write_dewif_v1_content( - currency, &keypair, pin, - )) + + let pin = if member_wallet { + gen_pin10()? + } else { + gen_pin6()? + }; + let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &pin); + let pubkey = keypair.public_key().to_base58(); + Ok(vec![dewif, pin, pubkey]) } -pub(super) fn get_pubkey(currency: &str, dewif: &str, pin: &str) -> Result { - let currency = parse_currency(currency)?; +pub(super) fn get_pubkey(currency: Currency, dewif: &str, pin: &str) -> Result { let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), dewif, @@ -126,15 +137,6 @@ pub(super) fn sign_several( } } -fn parse_currency(currency: &str) -> Result { - let currency_code = match currency { - "g1" => G1_CURRENCY, - "g1-test" | "gt" => G1_TEST_CURRENCY, - _ => return Err(DubpError::UnknownCurrencyName), - }; - Ok(Currency::from(currency_code)) -} - fn gen_pin2_inner(mut i: u32, pin: &mut String) { for _ in 0..2 { pin.push(to_char(i)); diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 2f29e58..65be056 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -59,6 +59,15 @@ fn char_ptr_prt_to_vec_str<'a>( Ok(str_vec) } +pub(crate) fn parse_currency(currency: &str) -> Result { + let currency_code = match currency { + "g1" => G1_CURRENCY, + "g1-test" | "gt" => G1_TEST_CURRENCY, + _ => return Err(DubpError::UnknownCurrencyName), + }; + Ok(Currency::from(currency_code)) +} + fn u32_to_language(i: u32) -> Result { match i { 0 => Ok(Language::English), @@ -73,7 +82,7 @@ pub extern "C" fn change_dewif_pin( currency: *const raw::c_char, dewif: *const raw::c_char, old_pin: *const raw::c_char, - new_pin: *const raw::c_char, + member_wallet: u32, ) { exec_async( port, @@ -81,10 +90,12 @@ pub extern "C" fn change_dewif_pin( let currency = char_ptr_to_str(currency)?; let dewif = char_ptr_to_str(dewif)?; let old_pin = char_ptr_to_str(old_pin)?; - let new_pin = char_ptr_to_str(new_pin)?; - Ok((currency, dewif, old_pin, new_pin)) + let member_wallet = member_wallet != 0; + Ok((currency, dewif, old_pin, member_wallet)) + }, + |(currency, dewif, old_pin, member_wallet)| { + dewif::change_pin(currency, dewif, old_pin, member_wallet) }, - |(currency, dewif, old_pin, new_pin)| dewif::change_pin(currency, dewif, old_pin, new_pin), ) } @@ -94,17 +105,19 @@ pub extern "C" fn gen_dewif( currency: *const raw::c_char, language: u32, mnemonic: *const raw::c_char, - pin: *const raw::c_char, + member_wallet: u32, ) { exec_async( port, || { let currency = char_ptr_to_str(currency)?; let mnemonic = char_ptr_to_str(mnemonic)?; - let pin = char_ptr_to_str(pin)?; - Ok((currency, language, mnemonic, pin)) + let member_wallet = member_wallet != 0; + Ok((currency, language, mnemonic, member_wallet)) + }, + |(currency, language, mnemonic, member_wallet)| { + dewif::gen_dewif(currency, language, mnemonic, member_wallet) }, - |(currency, language, mnemonic, pin)| dewif::gen_dewif(currency, language, mnemonic, pin), ) } @@ -138,7 +151,7 @@ pub extern "C" fn get_dewif_pubkey( exec_async( port, || { - let currency = char_ptr_to_str(currency)?; + let currency = parse_currency(char_ptr_to_str(currency)?)?; let dewif = char_ptr_to_str(dewif)?; let pin = char_ptr_to_str(pin)?; Ok((currency, dewif, pin)) diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index 35b4e8a..9856183 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -63,70 +63,25 @@ class DubpRust { return completer.future; } - static Future _genPin(PinLength pinLength) { - final completer = Completer(); - final sendPort = - singleCompletePort(completer, callback: _handleErr); - switch (pinLength) { - case PinLength.ten: - native.gen_pin10( - sendPort.nativePort, - ); - break; - case PinLength.eight: - native.gen_pin8( - sendPort.nativePort, - ); - break; - case PinLength.six: - default: - native.gen_pin6( - sendPort.nativePort, - ); - break; - } - return completer.future; - } - /// Change the pin code that encrypts the `dewif` keypair. static Future changeDewifPin( {String currency = "g1", String dewif, String oldPin, PinLength newPinLength = PinLength.six}) async { - // pin - String newPin = await _genPin(newPinLength); - // dewif - String newDewif; - { - final completer = Completer(); - final sendPort = - singleCompletePort(completer, callback: _handleErr); - native.change_dewif_pin( - sendPort.nativePort, - Utf8.toUtf8(currency), - Utf8.toUtf8(dewif), - Utf8.toUtf8(oldPin), - Utf8.toUtf8(newPin), - ); - newDewif = await completer.future; - } - // publicKey - String publicKey; - { - final completer = Completer(); - final sendPort = - singleCompletePort(completer, callback: _handleErr); - native.get_dewif_pubkey( - sendPort.nativePort, - Utf8.toUtf8(currency), - Utf8.toUtf8(newDewif), - Utf8.toUtf8(newPin), - ); - publicKey = await completer.future; - } + final completer = Completer>(); + final sendPort = singleCompletePort, List>(completer, + callback: _handleErrList); + native.change_dewif_pin( + sendPort.nativePort, + Utf8.toUtf8(currency), + Utf8.toUtf8(dewif), + Utf8.toUtf8(oldPin), + 0, + ); + List newWallet = await completer.future; - return Future.value(NewWallet._(newDewif, newPin, publicKey)); + return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); } /// Generate a wallet from a mnemonic phrase. @@ -141,37 +96,19 @@ class DubpRust { Language language = Language.english, String mnemonic, PinLength pinLength = PinLength.six}) async { - // pin - String pin = await _genPin(pinLength); - // publicKey - String publicKey; - { - final completer = Completer(); - final sendPort = - singleCompletePort(completer, callback: _handleErr); - native.mnemonic_to_pubkey( - sendPort.nativePort, - language.index, - Utf8.toUtf8(mnemonic), - ); - publicKey = await completer.future; - } - // dewif - String dewif; - { - final completer = Completer(); - final sendPort = - singleCompletePort(completer, callback: _handleErr); - native.gen_dewif( - sendPort.nativePort, - Utf8.toUtf8(currency), - language.index, - Utf8.toUtf8(mnemonic), - Utf8.toUtf8(pin), - ); - dewif = await completer.future; - } - return Future.value(NewWallet._(dewif, pin, publicKey)); + final completer = Completer>(); + final sendPort = singleCompletePort, List>(completer, + callback: _handleErrList); + native.gen_dewif( + sendPort.nativePort, + Utf8.toUtf8(currency), + language.index, + Utf8.toUtf8(mnemonic), + 0, + ); + List newWallet = await completer.future; + + return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); } /// Get pulblic key (in base 58) of `dewif` keypair. From 78740e13ecc49942bacaf9ab1f4f01c2f063d600 Mon Sep 17 00:00:00 2001 From: librelois Date: Sat, 9 Jan 2021 23:39:04 +0100 Subject: [PATCH 3/4] feat(dubp): replace param PinLen by SecretCodeType --- native/dubp_rs/src/dewif.rs | 133 ++++-------------------------- native/dubp_rs/src/error.rs | 2 + native/dubp_rs/src/inputs.rs | 69 ++++++++++++++++ native/dubp_rs/src/lib.rs | 89 +++++++------------- native/dubp_rs/src/secret_code.rs | 130 +++++++++++++++++++++++++++++ packages/dubp_rs/lib/dubp.dart | 45 +++++----- 6 files changed, 266 insertions(+), 202 deletions(-) create mode 100644 native/dubp_rs/src/inputs.rs create mode 100644 native/dubp_rs/src/secret_code.rs diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index 6fe856a..a7905e3 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -15,48 +15,26 @@ use crate::*; -pub(super) fn gen_pin6() -> Result { - let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; - Ok(gen_pin6_inner(i)) -} -pub(super) fn gen_pin8() -> Result { - let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; - let i2 = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; - let mut pin = gen_pin6_inner(i); - gen_pin2_inner(i2, &mut pin); - Ok(pin) -} -pub(super) fn gen_pin10() -> Result { - let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; - let i2 = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; - let mut pin = gen_pin6_inner(i); - gen_pin4_inner(i2, &mut pin); - Ok(pin) -} - -pub(super) fn change_pin( +pub(super) fn change_secret_code( currency: &str, dewif: &str, - old_pin: &str, + old_secret_code: &str, member_wallet: bool, + secret_code_type: SecretCodeType, ) -> Result, DubpError> { let currency = parse_currency(currency)?; let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), dewif, - old_pin, + old_secret_code, ) .map_err(DubpError::DewifReadError)?; if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - let new_pin = if member_wallet { - gen_pin10()? - } else { - gen_pin6()? - }; + let new_secret_code = gen_secret_code(member_wallet, secret_code_type)?; - let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &new_pin); + let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &new_secret_code); let pubkey = keypair.public_key().to_base58(); - Ok(vec![dewif, new_pin, pubkey]) + Ok(vec![dewif, new_secret_code, pubkey]) } else { Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) } @@ -64,24 +42,21 @@ pub(super) fn change_pin( pub(super) fn gen_dewif( currency: &str, - language: u32, + language: Language, mnemonic: &str, member_wallet: bool, + secret_code_type: SecretCodeType, ) -> Result, DubpError> { let currency = parse_currency(currency)?; - let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?) - .map_err(|_| DubpError::WrongLanguage)?; + let mnemonic = + Mnemonic::from_phrase(mnemonic, language).map_err(|_| DubpError::WrongLanguage)?; let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic); let keypair = KeyPairFromSeed32Generator::generate(seed); - let pin = if member_wallet { - gen_pin10()? - } else { - gen_pin6()? - }; - let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &pin); + let secret_code = gen_secret_code(member_wallet, secret_code_type)?; + let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &secret_code); let pubkey = keypair.public_key().to_base58(); - Ok(vec![dewif, pin, pubkey]) + Ok(vec![dewif, secret_code, pubkey]) } pub(super) fn get_pubkey(currency: Currency, dewif: &str, pin: &str) -> Result { @@ -136,83 +111,3 @@ pub(super) fn sign_several( Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) } } - -fn gen_pin2_inner(mut i: u32, pin: &mut String) { - for _ in 0..2 { - pin.push(to_char(i)); - i /= 35; - } -} -fn gen_pin4_inner(mut i: u32, pin: &mut String) { - for _ in 0..4 { - pin.push(to_char(i)); - i /= 35; - } -} -fn gen_pin6_inner(mut i: u32) -> String { - let mut pin = String::new(); - - for _ in 0..6 { - pin.push(to_char(i)); - i /= 35; - } - - pin -} - -fn to_char(i: u32) -> char { - match i % 35 { - 0 => 'Z', - 1 => '1', - 2 => '2', - 3 => '3', - 4 => '4', - 5 => '5', - 6 => '6', - 7 => '7', - 8 => '8', - 9 => '9', - 10 => 'A', - 11 => 'B', - 12 => 'C', - 13 => 'D', - 14 => 'E', - 15 => 'F', - 16 => 'G', - 17 => 'H', - 18 => 'I', - 19 => 'J', - 20 => 'K', - 21 => 'L', - 22 => 'M', - 23 => 'N', - 24 => 'O', - 25 => 'P', - 26 => 'Q', - 27 => 'R', - 28 => 'S', - 29 => 'T', - 30 => 'U', - 31 => 'V', - 32 => 'W', - 33 => 'X', - 34 => 'Y', - _ => unreachable!(), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_gen_pin_6() { - assert_eq!("ZZZZZZ", &gen_pin6_inner(0)); - assert_eq!("YZZZZZ", &gen_pin6_inner(34)); - assert_eq!("Z1ZZZZ", &gen_pin6_inner(35)); - assert_eq!("ZZ1ZZZ", &gen_pin6_inner(1225)); - assert_eq!("2Z1ZZZ", &gen_pin6_inner(1227)); - assert_eq!("Z11ZZZ", &gen_pin6_inner(1260)); - assert_eq!("111ZZZ", &gen_pin6_inner(1261)); - } -} diff --git a/native/dubp_rs/src/error.rs b/native/dubp_rs/src/error.rs index 63bd5ec..b8f3d41 100644 --- a/native/dubp_rs/src/error.rs +++ b/native/dubp_rs/src/error.rs @@ -22,6 +22,8 @@ pub(crate) enum DubpError { DewifReadError(DewifReadError), #[error("I/O error: {0}")] IoErr(io::Error), + #[error("Digits secret code forbid for member wallet")] + DigitsCodeForbidForMemberWallet, #[error("A given parameter is null")] NullParamErr, #[error("fail to generate random bytes")] diff --git a/native/dubp_rs/src/inputs.rs b/native/dubp_rs/src/inputs.rs new file mode 100644 index 0000000..7959580 --- /dev/null +++ b/native/dubp_rs/src/inputs.rs @@ -0,0 +1,69 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::*; + +pub(crate) enum SecretCodeType { + Digits, + Letters, +} +impl From for SecretCodeType { + fn from(i: u32) -> Self { + if i == 0 { + SecretCodeType::Digits + } else { + SecretCodeType::Letters + } + } +} + +pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a str, DubpError> { + if c_char_ptr.is_null() { + Err(DubpError::NullParamErr) + } else { + unsafe { CStr::from_ptr(c_char_ptr).to_str() }.map_err(DubpError::Utf8Error) + } +} + +pub(crate) fn char_ptr_prt_to_vec_str<'a>( + char_ptr_ptr: *const *const raw::c_char, + len: u32, +) -> Result, DubpError> { + let len = len as usize; + let char_ptr_slice: &[*const raw::c_char] = + unsafe { std::slice::from_raw_parts(char_ptr_ptr, len) }; + let mut str_vec = Vec::with_capacity(len); + for char_ptr in char_ptr_slice { + str_vec.push(char_ptr_to_str(*char_ptr)?); + } + Ok(str_vec) +} + +pub(crate) fn parse_currency(currency: &str) -> Result { + let currency_code = match currency { + "g1" => G1_CURRENCY, + "g1-test" | "gt" => G1_TEST_CURRENCY, + _ => return Err(DubpError::UnknownCurrencyName), + }; + Ok(Currency::from(currency_code)) +} + +pub(crate) fn u32_to_language(i: u32) -> Result { + match i { + 0 => Ok(Language::English), + 1 => Ok(Language::French), + _ => Err(DubpError::UnknownLanguage), + } +} diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 65be056..e0280e0 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -18,10 +18,14 @@ mod r#async; mod dewif; mod error; +mod inputs; mod mnemonic; +mod secret_code; use crate::error::{DartRes, DubpError}; +use crate::inputs::*; use crate::r#async::exec_async; +use crate::secret_code::gen_secret_code; use allo_isolate::{IntoDart, Isolate}; use dup_crypto::{ bases::b58::ToBase58, @@ -37,52 +41,14 @@ use once_cell::sync::Lazy; use std::{ffi::CStr, io, os::raw}; use thiserror::Error; -pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a str, DubpError> { - if c_char_ptr.is_null() { - Err(DubpError::NullParamErr) - } else { - unsafe { CStr::from_ptr(c_char_ptr).to_str() }.map_err(DubpError::Utf8Error) - } -} - -fn char_ptr_prt_to_vec_str<'a>( - char_ptr_ptr: *const *const raw::c_char, - len: u32, -) -> Result, DubpError> { - let len = len as usize; - let char_ptr_slice: &[*const raw::c_char] = - unsafe { std::slice::from_raw_parts(char_ptr_ptr, len) }; - let mut str_vec = Vec::with_capacity(len); - for char_ptr in char_ptr_slice { - str_vec.push(char_ptr_to_str(*char_ptr)?); - } - Ok(str_vec) -} - -pub(crate) fn parse_currency(currency: &str) -> Result { - let currency_code = match currency { - "g1" => G1_CURRENCY, - "g1-test" | "gt" => G1_TEST_CURRENCY, - _ => return Err(DubpError::UnknownCurrencyName), - }; - Ok(Currency::from(currency_code)) -} - -fn u32_to_language(i: u32) -> Result { - match i { - 0 => Ok(Language::English), - 1 => Ok(Language::French), - _ => Err(DubpError::UnknownLanguage), - } -} - #[no_mangle] -pub extern "C" fn change_dewif_pin( +pub extern "C" fn change_dewif_secret_code( port: i64, currency: *const raw::c_char, dewif: *const raw::c_char, old_pin: *const raw::c_char, member_wallet: u32, + secret_code_type: u32, ) { exec_async( port, @@ -91,10 +57,11 @@ pub extern "C" fn change_dewif_pin( let dewif = char_ptr_to_str(dewif)?; let old_pin = char_ptr_to_str(old_pin)?; let member_wallet = member_wallet != 0; - Ok((currency, dewif, old_pin, member_wallet)) + let secret_code_type = SecretCodeType::from(secret_code_type); + Ok((currency, dewif, old_pin, member_wallet, secret_code_type)) }, - |(currency, dewif, old_pin, member_wallet)| { - dewif::change_pin(currency, dewif, old_pin, member_wallet) + |(currency, dewif, old_pin, member_wallet, secret_code_type)| { + dewif::change_secret_code(currency, dewif, old_pin, member_wallet, secret_code_type) }, ) } @@ -106,17 +73,32 @@ pub extern "C" fn gen_dewif( language: u32, mnemonic: *const raw::c_char, member_wallet: u32, + secret_code_type: u32, ) { exec_async( port, || { let currency = char_ptr_to_str(currency)?; + let language = u32_to_language(language)?; let mnemonic = char_ptr_to_str(mnemonic)?; let member_wallet = member_wallet != 0; - Ok((currency, language, mnemonic, member_wallet)) + let secret_code_type = SecretCodeType::from(secret_code_type); + Ok(( + currency, + language, + mnemonic, + member_wallet, + secret_code_type, + )) }, - |(currency, language, mnemonic, member_wallet)| { - dewif::gen_dewif(currency, language, mnemonic, member_wallet) + |(currency, language, mnemonic, member_wallet, secret_code_type)| { + dewif::gen_dewif( + currency, + language, + mnemonic, + member_wallet, + secret_code_type, + ) }, ) } @@ -126,21 +108,6 @@ pub extern "C" fn gen_mnemonic(port: i64, language: u32) { Isolate::new(port).post(DartRes::from(mnemonic::gen_mnemonic(language))); } -#[no_mangle] -pub extern "C" fn gen_pin6(port: i64) { - Isolate::new(port).post(DartRes::from(dewif::gen_pin6())); -} - -#[no_mangle] -pub extern "C" fn gen_pin8(port: i64) { - Isolate::new(port).post(DartRes::from(dewif::gen_pin8())); -} - -#[no_mangle] -pub extern "C" fn gen_pin10(port: i64) { - Isolate::new(port).post(DartRes::from(dewif::gen_pin10())); -} - #[no_mangle] pub extern "C" fn get_dewif_pubkey( port: i64, diff --git a/native/dubp_rs/src/secret_code.rs b/native/dubp_rs/src/secret_code.rs new file mode 100644 index 0000000..f9581e4 --- /dev/null +++ b/native/dubp_rs/src/secret_code.rs @@ -0,0 +1,130 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::*; + +pub(crate) fn gen_secret_code( + member_wallet: bool, + secret_code_type: SecretCodeType, +) -> Result { + match secret_code_type { + SecretCodeType::Digits => { + if member_wallet { + Err(DubpError::DigitsCodeForbidForMemberWallet) + } else { + gen_random_digits(8) + } + } + SecretCodeType::Letters => { + if member_wallet { + gen_random_letters(10) + } else { + gen_random_letters(6) + } + } + } +} + +fn gen_random_digits(n: usize) -> Result { + let mut digits_string = dup_crypto::rand::gen_u32() + .map_err(|_| DubpError::RandErr)? + .to_string(); + digits_string.truncate(n); + + if digits_string.len() == n { + Ok(digits_string) + } else { + let missing_digits = n - digits_string.len(); + let mut digits_string_ = String::with_capacity(n); + for _ in 0..missing_digits { + digits_string_.push('0'); + } + digits_string_.push_str(&digits_string); + Ok(digits_string_) + } +} + +fn gen_random_letters(mut n: usize) -> Result { + let mut letters = String::with_capacity(n); + while n >= 6 { + letters.push_str(&gen_random_letters_inner(6)?); + n -= 6; + } + letters.push_str(&gen_random_letters_inner(n)?); + + Ok(letters) +} + +fn gen_random_letters_inner(n: usize) -> Result { + let mut i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?; + let mut letters = String::new(); + + for _ in 0..n { + letters.push(to_char(i)); + i /= 26; + } + + Ok(letters) +} + +fn to_char(i: u32) -> char { + match i % 26 { + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + 4 => 'E', + 5 => 'F', + 6 => 'G', + 7 => 'H', + 8 => 'I', + 9 => 'J', + 10 => 'K', + 11 => 'L', + 12 => 'M', + 13 => 'N', + 14 => 'O', + 15 => 'P', + 16 => 'Q', + 17 => 'R', + 18 => 'S', + 19 => 'T', + 20 => 'U', + 21 => 'V', + 22 => 'W', + 23 => 'X', + 24 => 'Y', + 25 => 'Z', + _ => unreachable!(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_gen_random_digits() -> Result<(), DubpError> { + assert_eq!(gen_random_digits(8)?.len(), 8); + //println!("TMP: {}", gen_random_digits(8)?); + Ok(()) + } + #[test] + fn test_gen_random_letters() -> Result<(), DubpError> { + assert_eq!(gen_random_letters(6)?.len(), 6); + //println!("TMP: {}", gen_random_letters(6)?); + Ok(()) + } +} diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index 9856183..e2f1d2e 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -19,7 +19,7 @@ class NewWallet { /// DEWIF: Encrypted wallet String dewif; - /// Pin code + /// Secret code String pin; /// Public key @@ -28,16 +28,13 @@ class NewWallet { NewWallet._(this.dewif, this.pin, this.publicKey); } -/// Pin code length -enum PinLength { - /// 6 characters - six, +/// Secret code type +enum SecretCodeType { + /// Digits + digits, - /// 8 characters - eight, - - /// 10 characters - ten, + /// Letters + letters, } /// DUBP Rust utilities @@ -63,21 +60,23 @@ class DubpRust { return completer.future; } - /// Change the pin code that encrypts the `dewif` keypair. - static Future changeDewifPin( - {String currency = "g1", - String dewif, - String oldPin, - PinLength newPinLength = PinLength.six}) async { + /// Change the secret code that encrypts the `dewif` keypair. + static Future changeDewifPin({ + String currency = "g1", + String dewif, + String oldPin, + SecretCodeType secretCodeType = SecretCodeType.letters, + }) async { final completer = Completer>(); final sendPort = singleCompletePort, List>(completer, callback: _handleErrList); - native.change_dewif_pin( + native.change_dewif_secret_code( sendPort.nativePort, Utf8.toUtf8(currency), Utf8.toUtf8(dewif), Utf8.toUtf8(oldPin), 0, + secretCodeType.index, ); List newWallet = await completer.future; @@ -91,11 +90,12 @@ class DubpRust { /// /// If the wallet to be generated is not dedicated to the Ğ1 currency, you /// must indicate the currency for which this wallet will be used. - static Future genWalletFromMnemonic( - {String currency = "g1", - Language language = Language.english, - String mnemonic, - PinLength pinLength = PinLength.six}) async { + static Future genWalletFromMnemonic({ + String currency = "g1", + Language language = Language.english, + String mnemonic, + SecretCodeType secretCodeType = SecretCodeType.letters, + }) async { final completer = Completer>(); final sendPort = singleCompletePort, List>(completer, callback: _handleErrList); @@ -105,6 +105,7 @@ class DubpRust { language.index, Utf8.toUtf8(mnemonic), 0, + secretCodeType.index, ); List newWallet = await completer.future; From 5ad10a5aaf8533d5088ade1b14395e5fe8fe0f5d Mon Sep 17 00:00:00 2001 From: librelois Date: Sat, 9 Jan 2021 23:46:54 +0100 Subject: [PATCH 4/4] doc(dubp): update README --- packages/dubp_rs/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/dubp_rs/README.md b/packages/dubp_rs/README.md index 305dcb4..2c27fe8 100644 --- a/packages/dubp_rs/README.md +++ b/packages/dubp_rs/README.md @@ -57,7 +57,7 @@ The project use [`dart-bindgen`](https://github.com/sunshine-protocol/dart-bindg * 32bit emulator (`x86`/`i686` architecture) ```sh -cargo make android-dev32 +cargo bd ``` * 64bit emulator (`x86_64` architecture) @@ -71,7 +71,7 @@ cargo make android-dev In the Root of the project simply run: ```sh -cargo make +cargo br ``` WARNING: This will take a lot of time because the Rust code will have to be recompiled for each different architecture, 4 times for android and 2 times for iOS! @@ -113,7 +113,7 @@ static Future genWalletFromMnemonic({ String currency = "g1", Language language = Language.english, String mnemonic, - PinLength pinLength = PinLength.six + SecretCodeType secretCodeType = SecretCodeType.letters }); ``` @@ -129,13 +129,13 @@ NewWallet new_wallet = await DubpRust.genWalletFromMnemonic( ); ``` -You can choose a different length for the pin code (6 by default): +You can choose a different secret code type: ```dart NewWallet new_wallet = await DubpRust.genWalletFromMnemonic( language: Language.english, mnemonic: "tongue cute mail fossil great frozen same social weasel impact brush kind", - pinLength: PinLength.eight + secretCodeType: SecretCodeType.digits ); ``` @@ -164,9 +164,9 @@ String signature = await DubpRust.sign( ); ``` -### Change pin code +### Change secret code -You can change the pin code that encrypts the [DEWIF]. +You can change the secret code that encrypts the [DEWIF]. #### Function signature @@ -175,7 +175,7 @@ static Future changeDewifPin({ String currency = "g1", String dewif, String oldPin, - PinLength newPinLength = PinLength.six + SecretCodeType secretCodeType = SecretCodeType.letters }); ``` @@ -186,7 +186,7 @@ If the wallet is not dedicated to the Ğ1 currency, you must indicate the curren ```dart NewWallet new_wallet = await DubpRust.changeDewifPin( dewif: "AAAAARAAAAGfFDAs+jVZYkfhBlHZZ2fEQIvBqnG16g5+02cY18wSOjW0cUg2JV3SUTJYN2CrbQeRDwGazWnzSFBphchMmiL0", - oldPin: "CDJ4UB", + oldPin: "CDJAUB", ); ```